<pre class='metadata'>
Title: Service Workers Nightly
Status: WD
ED: https://w3c.github.io/ServiceWorker/spec/service_worker/
TR: https://www.w3.org/TR/service-workers/
Shortname: service-workers
Level:
Previous version: https://www.w3.org/TR/2015/WD-service-workers-20150625/
Previous version: https://www.w3.org/TR/2015/WD-service-workers-20150205/
Previous version: https://www.w3.org/TR/2014/WD-service-workers-20141118/
Previous version: https://www.w3.org/TR/2014/WD-service-workers-20140508/
Editor: Alex Russell, Google, slightlyoff@chromium.org
Editor: Jungkee Song, Samsung Electronics, jungkee.song@samsung.com
Editor: Jake Archibald, Google, jakearchibald@chromium.org
Editor: Marijn Kruisselbrink, Google, mek@chromium.org
Repository: w3c/ServiceWorker
Group: webplatform
Status Text: This is a living document addressing new features including foreign fetch and header-based installation, etc. Readers need to be aware that this specification includes unstable features. Implementers interested in implementing this specification should refer to the latest TR of <a href="https://w3c.github.io/ServiceWorker/spec/service_worker_1/">Service Workers 1</a> instead.
Abstract: This specification describes a method that enables applications to take advantage of persistent background processing, including hooks to enable bootstrapping of web applications while offline.
Abstract:
Abstract: The core of this system is an event-driven <a>Web Worker</a>, which responds to events dispatched from documents and other sources. A system for managing installation, versions, and upgrades is provided.
Abstract:
Abstract: The service worker is a generic entry point for event-driven background processing in the Web Platform that is <a href="#extensibility">extensible by other specifications</a>.
Ignored Terms: javascript global environment, worker environment, worker environments, document environment, document environments, referrer source, script execution environment, script execution environments, code entry-point, jump to a code entry point, used flag, process response body, http equivalent codes
Markup Shorthands: css no
</pre>

<pre class=biblio>
{
  "promises-guide": {
    "href": "https://www.w3.org/2001/tag/doc/promises-guide",
    "title": "Writing Promise-Using Specifications",
    "date": "24 July 2015",
    "status": "Finding of the W3C TAG",
    "publisher": "W3C TAG"
  },
  "unsanctioned-tracking": {
    "href": "https://www.w3.org/2001/tag/doc/unsanctioned-tracking/",
    "title": "Unsanctioned Web Tracking",
    "date": "17 July 2015",
    "status": "Finding of the W3C TAG",
    "publisher": "W3C TAG"
  }
}
</pre>

<pre class=link-defaults>
spec: dom
    type: dfn
        text: invoke
    type: interface
        text: Document
        text: Event
        text: EventTarget

spec: html; type: element; text: link
spec: html; type: dfn
    text: a browsing context is discarded
    text: about:blank
    text: active document
    text: api base url
    text: api url character encoding
    text: application cache
    text: auxiliary browsing context
    text: browsing context
    text: discard a document
    text: document base url
    text: effective script origin
    text: entry settings object
    text: environment settings object
    text: event handler
    text: event handler event type
    text: event handler idl attributes
    text: event loop
    text: exceptions enabled flag
    text: focusing steps
    text: global object
    text: incumbent settings object
    text: in parallel
    text: kill a worker
    text: list of active timers
    text: navigate
    text: nested browsing context
    text: neutered
    text: parent browsing context
    text: queue a task
    text: relevant settings object
    text: replacement enabled
    text: responsible browsing context
    text: responsible document
    text: responsible event loop
    text: same origin
    text: script
    text: settings object
    text: source browsing context
    text: structured clone
    text: task sources
    text: tasks
    text: the environment settings object's global object
    text: the global object's realm
    text: the worker's documents
    text: top-level browsing context
    text: triggered by user activation
    text: trusted event
    text: unicode serialisation of an origin
    text: unload a document
    text: user interaction task source
    text: utf-8 decode

spec: url; type: dfn
    text: is local

spec: webidl; type: dfn;
    text: exception
    text: partial interface
    text: present
</pre>

<pre class=anchors>
spec: dom-ls; urlPrefix: https://dom.spec.whatwg.org/
    type: dfn; text: ASCII case-insensitive; url: ascii-case-insensitive

spec: ecma-262; urlPrefix: http://www.ecma-international.org/ecma-262/6.0/
    type: dfn
        text: Assert; url: sec-algorithm-conventions
        text: [[Call]]; url: sec-ecmascript-function-objects-call-thisargument-argumentslist
        text: map objects; url: sec-map-objects
        text: promise; url: sec-promise-objects
        url: sec-list-and-record-specification-type
            text: List
            text: Record

spec: csp2; urlPrefix: https://w3c.github.io/webappsec-csp/2/
    type: dfn
        text: enforce
        text: monitor

spec: fetch; urlPrefix: https://fetch.spec.whatwg.org/
    type: dfn
        text: basic filtered response; url: concept-filtered-response-basic
        text: cancel a ReadableStream; url: concept-cancel-readablestream
        text: close ReadableStream; url: concept-close-readablestream
        text: construct a ReadableStream; url: concept-construct-readablestream
        text: CORS filtered response; url: concept-filtered-response-cors
        text: disturbed; url: concept-body-disturbed
        text: empty; url: concept-empty-readablestream
        text: enqueue a chunk to ReadableStream; url: concept-enqueue-readablestream
        text: error ReadableStream; url: concept-error-readablestream
        text: errored; url: concept-readablestream-errored
        text: extract a mime type; url: concept-header-extract-mime-type
        text: fetch; url: concept-fetch
        text: filtered response; url: concept-filtered-response
        text: get a reader; url: concept-get-reader
        text: header; url: concept-header
        text: http fetch; url: concept-http-fetch
        text: internal response; url: concept-internal-response
        text: locked; url: concept-body-locked
        text: navigation request
        text: network error; url: concept-network-error
        text: non-subresource request
        text: ok status; url: ok-status
        text: opaque filtered response; url: concept-filtered-response-opaque
        text: opaque-redirect filtered response; url: concept-filtered-response-opaque-redirect
        text: potential-navigation-or-subresource request
        text: process response
        text: process response end-of-file
        text: read a chunk from a ReadableStream; url: concept-read-chunk-from-readablestream
        text: read all bytes; url: concept-read-all-bytes-from-readablestream
        text: ReadableStream; url: concept-readablestream
        text: request; for: fetch; url: concept-request
        text: response; for: fetch; url: concept-response
        text: skip service worker flag
        text: stream; url: concept-body-stream
        text: subresource request
        text: synchronous flag
        text: terminate; url: concept-fetch-terminate
        text: guard; for: headers; url: concept-headers-guard
        for: header; urlPrefix: #concept-header-
            text: name
            text: parsing; url: parse
        for: request; urlPrefix: #concept-request-
            text: cache mode
            text: client
            text: destination
            text: header list
            text: initiator
            text: method
            text: origin
            text: redirect mode
            text: request
            text: response tainting
            text: url
        for: response; urlPrefix: #concept-response-
            text: body
            text: cache state
            text: CORS-exposed header-name list
            text: header list
            text: response
            text: status
            text: termination reason
            text: type
    type: interface
        text: Headers
        text: Request
        text: RequestInfo
        text: Response
    type: attribute; for: Request
        text: headers; url: dom-request-headers
    type: method
        text: get(name); for: Headers; url: dom-headers-get
        text: fetch(input, init); for: GlobalFetch; url: dom-global-fetch

spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/
    type: dfn
        urlPrefix: browsers.html
            text: origin; for: resource; url: origin-2
            text: browsing context is discarded
        urlPrefix: infrastructure.html
            text: read only array; url: dfn-read-only-array
            text: StructuredCloneWithTransfer
        urlPrefix: interaction.html
            text: has focus steps
        urlPrefix: semantics.html
            text: external resource link
        urlPrefix: webappapis.html
            text: classic script
            text: creation url
            text: dom manipulation task source
            text: fire a simple event
            text: https state; for: environment settings object
            text: module script
            text: realm execution context
            text: relevant Realm; url: concept-relevant-realm
            text: relevant global object; url: concept-relevant-global
            text: report the error
            text: run a classic script
            text: run a module script
            text: script; url: concept-script
            text: task queue; for: event loop
        urlPrefix: workers.html
            text: get a fetch result
            text: import scripts into worker global scope
            text: kill a worker
            text: postprocess the fetch result
            text: runtime script errors handling; url: runtime-script-errors-2
            text: shared workers
            text: terminate a worker
            text: validate the state
            text: web worker; url: workers
            for: workerglobalscope; urlPrefix: #concept-workerglobalscope-
                text: https state
                text: type
                text: url
    type: event
        urlPrefix: indices.html
            text: DOMContentLoaded; for: Document; url: event-domcontentloaded
            text: message; for: Window; url: event-message

spec: page-visibility; urlPrefix: https://www.w3.org/TR/page-visibility/
    type: enum; text: VisibilityState; url: VisibilityState
    type: attribute; text: visibilityState; for: Document; url: dom-document-visibilitystate

spec: powerful-features; urlPrefix: https://w3c.github.io/webappsec/specs/powerfulfeatures/#
    type: dfn
        text: is origin potentially trustworthy; url: is-origin-trustworthy
        text: risks associated with insecure contexts; url: threat-risks
        text: secure context

spec: promises-guide; urlPrefix: https://www.w3.org/2001/tag/doc/promises-guide#
    type: dfn
        text: waiting for all
        text: transforming; url: transforming-by

spec: quota-api; urlPrefix: http://www.w3.org/TR/quota-api/
    type: attribute; for: ServiceWorkerGlobalScope
        text: onbeforeevicted; url: widl-ServiceWorkerGlobalScope-onbeforeevicted
        text: onevicted; url: widl-ServiceWorkerGlobalScope-onevicted

spec: rfc5988; urlPrefix: https://tools.ietf.org/html/rfc5988
    type: dfn
        text: context IRI; url: section-5.2
        text: target attribute; url: section-5.4
        text: target IRI; url: section-5.1

spec: rfc7230; urlPrefix: https://tools.ietf.org/html/rfc7230
    type: dfn
        text: field-value; for: http; url: section-3.2

spec: rfc7231; urlPrefix: https://tools.ietf.org/html/rfc7231
    type: dfn
        text: Vary; url: section-7.1.4

spec: url; urlPrefix: https://url.spec.whatwg.org/
    type: dfn
        text: parsing; for: url; url: concept-url-parser
        text: serialized; for: url; url: concept-url-serializer

spec: webidl; urlPrefix: https://heycam.github.io/webidl/
    type: dfn
        text: throw; url: dfn-throw
    type: exception
        text: DataCloneError
        text: InvalidAccessError
        text: InvalidStateError
        text: NetworkError
        text: NotFoundError
        text: QuotaExceededError
        text: SecurityError
</pre>

<section>
  <h2 id='motivations'>Motivations</h2>

  <em>This section is non-normative.</em>

  <p>Web Applications traditionally assume that the network is reachable. This assumption pervades the platform. HTML documents are loaded over HTTP and traditionally fetch all of their sub-resources via subsequent HTTP requests. This places web content at a disadvantage versus other technology stacks.</p>

  <p>The <a href="#dfn-service-worker">service worker</a> is designed first to redress this balance by providing a Web Worker context, which can be started by a runtime when navigations are about to occur. This event-driven worker is registered against an origin and a path (or pattern), meaning it can be consulted when navigations occur to that location. Events that correspond to network requests are dispatched to the worker and the responses generated by the worker may override default network stack behavior. This puts the <a href="#dfn-service-worker">service worker</a>, conceptually, between the network and a document renderer, allowing the <a href="#dfn-service-worker">service worker</a> to provide content for documents, even while offline.</p>

  <p>Web developers familiar with previous attempts to solve the offline problem have reported a deficit of flexibility in those solutions. As a result, the <a href="#dfn-service-worker">service worker</a> is highly procedural, providing a maximum of flexibility at the price of additional complexity for developers. Part of this complexity arises from the need to keep <a href="#dfn-service-worker">service workers</a> responsive in the face of a single-threaded execution model. As a result, APIs exposed by <a href="#dfn-service-worker">service workers</a> are almost entirely asynchronous, a pattern familiar in other JavaScript contexts but accentuated here by the need to avoid blocking document and resource loading.</p>

  <p>Developers using the <a lt="application cache">HTML5 Application Cache</a> have also <a href="http://alistapart.com/article/application-cache-is-a-douchebag">reported that several attributes</a> of the design contribute to <a href="http://alistapart.com/article/application-cache-is-a-douchebag#section6">unrecoverable errors</a>. A key design principle of the <a href="#dfn-service-worker">service worker</a> is that errors should <em>always</em> be recoverable. Many details of the update process of <a href="#dfn-service-worker">service workers</a> are designed to avoid these hazards.</p>

  <p><a href="#dfn-service-worker">Service workers</a> are started and kept alive by their relationship to events, not documents. This design borrows heavily from developer and vendor experience with <a>Shared Workers</a> and <a href="https://developer.chrome.com/extensions/background_pages">Chrome Background Pages</a>. A key lesson from these systems is the necessity to time-limit the execution of background processing contexts, both to conserve resources and to ensure that background context loss and restart is top-of-mind for developers. As a result, <a href="#dfn-service-worker">service workers</a> bear more than a passing resemblance to <a href="https://developer.chrome.com/extensions/event_pages">Chrome Event Pages</a>, the successor to Background Pages. <a href="#dfn-service-worker">Service workers</a> may be started by user agents <em>without an attached document</em> and may be killed by the user agent at nearly any time. Conceptually, <a href="#dfn-service-worker">service workers</a> can be thought of as Shared Workers that can start, process events, and die without ever handling messages from documents. Developers are advised to keep in mind that <a href="#dfn-service-worker">service workers</a> may be started and killed many times a second.</p>

  <p><a href="#dfn-service-worker">Service workers</a> are generic, event-driven, time-limited script contexts that run at an origin. These properties make them natural endpoints for a range of runtime services that may outlive the context of a particular document, e.g. handling push notifications, background data synchronization, responding to resource requests from other origins, or receiving centralized updates to expensive-to-calculate data (e.g., geolocation or gyroscope).</p>
</section>

<section>
  <h2 id="model">Model</h2>

  <section dfn-for="service worker">
    <h3 id="service-worker-concept">Service Worker</h3>

    <p>A <dfn id="dfn-service-worker" for="">service worker</dfn> is a type of <a>web worker</a>. A <a href="#dfn-service-worker">service worker</a> executes in the registering <a href="#dfn-service-worker-client">service worker client</a>'s <a for="resource">origin</a>.</p>
    <p>A <a href="#dfn-service-worker">service worker</a> has an associated <dfn id="dfn-state">state</dfn>, which is one of <em>parsed</em>, <em>installing</em>, <em>installed</em>, <em>activating</em>, <em>activated</em>, and <em>redundant</em>. It is initially <em>parsed</em>.</p>
    <p>A <a href="#dfn-service-worker">service worker</a> has an associated <dfn id="dfn-script-url">script url</dfn> (a <a for="url">URL</a>).</p>
    <p>A <a href="#dfn-service-worker">service worker</a> has an associated <dfn id="dfn-type">type</dfn> which is either "<code>classic</code>" or "<code>module</code>". Unless stated otherwise, it is "<code>classic</code>".</p>
    <p>A <a href="#dfn-service-worker">service worker</a> has an associated <dfn id="dfn-containing-service-worker-registration">containing service worker registration</dfn> (a <a href="#dfn-service-worker-registration">service worker registration</a>), which contains itself.</p>
    <p>A <a href="#dfn-service-worker">service worker</a> has an associated <dfn id="dfn-service-worker-id">id</dfn> (an opaque string), which uniquely identifies itself during the lifetime of its <a href="#dfn-containing-service-worker-registration">containing service worker registration</a>.</p>
    <p>A <a href="#dfn-service-worker">service worker</a> is dispatched a set of <dfn id="dfn-lifecycle-events">lifecycle events</dfn>, <a href="#service-worker-global-scope-install-event">install</a> and <a href="#service-worker-global-scope-activate-event">activate</a>, and <dfn id="dfn-functional-events">functional events</dfn> including <a href="#service-worker-global-scope-fetch-event">fetch</a>.</p>
    <p>A <a href="#dfn-service-worker">service worker</a> has an associated <dfn id="dfn-script-resource">script resource</dfn> (a <a>script</a>), which represents its own script resource. It is initially set to null. A <a href="#dfn-script-resource">script resource</a> has an associated <dfn id="dfn-has-ever-been-evaluated-flag">has ever been evaluated flag</dfn>. It is initially unset. A <a href="#dfn-script-resource">script resource</a> has an associated <dfn id="dfn-https-state">HTTPS state</dfn> which is "<code>none</code>", "<code>deprecated</code>", or "<code>modern</code>". Unless stated otherwise, it is "<code>none</code>".</p>
    <p>A <a href="#dfn-service-worker">service worker</a> has an associated <dfn id="dfn-script-resource-map">script resource map</dfn> which is a <a>List</a> of the <a>Record</a> {\[[key]], \[[value]]} where \[[key]] is a <a for="url">URL</a> and \[[value]] is a <a for="response">response</a>.</p>
    <p>A <a href="#dfn-service-worker">service worker</a> has an associated <dfn id="dfn-skip-waiting-flag">skip waiting flag</dfn>. Unless stated otherwise it is unset.</p>
    <p>A <a href="#dfn-service-worker">service worker</a> has an associated <dfn id="dfn-imported-scripts-updated-flag">imported scripts updated flag</dfn>. It is initially unset.</p>
    <p>A <a href="#dfn-service-worker">service worker</a> has an associated <dfn id="dfn-set-of-event-types-to-handle">set of event types to handle</dfn> whose element type is an <a>event listener</a>'s event type. It is initially set to null.</p>
    <p>A <a href="#dfn-service-worker">service worker</a> has an associated <dfn id="dfn-foreign-fetch-scopes">list of foreign fetch scopes</dfn> whose element type is a <a for="url">URL</a>. It is initially empty.</p>
    <p>A <a href="#dfn-service-worker">service worker</a> has an associated <dfn id="dfn-foreign-fetch-origins">list of foreign fetch origins</dfn> whose element type is a <a for="url">URL</a>. It is initially empty.</p>

    <section>
      <h4 id="service-worker-lifetime">Lifetime</h4>

      <p>The lifetime of a <a href="#dfn-service-worker">service worker</a> is tied to the execution lifetime of events and not references held by <a href="#dfn-service-worker-client">service worker clients</a> to the <code><a href="#service-worker-interface">ServiceWorker</a></code> object.</p>
      <p>A user agent <em class="rfc2119" title="MAY">may</em> <a href="#terminate-service-worker-algorithm">terminate</a> <a href="#dfn-service-worker">service workers</a> at any time it:</p>
      <ul>
        <li>Has no event to handle.</li>
        <li>Detects abnormal operation: such as infinite loops and tasks exceeding imposed time limits (if any) while handling the events.</li>
      </ul>
    </section>
  </section>

  <section dfn-for="service worker registration">
    <h3 id="service-worker-registration-concept">Service Worker Registration</h3>

    <p>A <dfn id="dfn-service-worker-registration" for="">service worker registration</dfn> is a tuple of a <a href="#dfn-scope-url">scope url</a> and a set of <a href="#dfn-service-worker">service workers</a>, an <a href="#dfn-installing-worker">installing worker</a>, a <a href="#dfn-waiting-worker">waiting worker</a>, and an <a href="#dfn-active-worker">active worker</a>. A user agent <em class="rfc2119" title="MAY">may</em> enable many <a href="#dfn-service-worker-registration">service worker registrations</a> at a single origin so long as the <a href="#dfn-scope-url">scope url</a> of the <a href="#dfn-service-worker-registration">service worker registration</a> differs. A <a href="#dfn-service-worker-registration">service worker registration</a> of an identical <a href="#dfn-scope-url">scope url</a> when one already exists in the user agent causes the existing <a href="#dfn-service-worker-registration">service worker registration</a> to be replaced.</p>
    <p>A <a href="#dfn-service-worker-registration">service worker registration</a> has an associated <dfn id="dfn-scope-url">scope url</dfn> (a <a for="url">URL</a>).</p>
    <p>A <a href="#dfn-service-worker-registration">service worker registration</a> has an associated <dfn id="dfn-registration-script-url">registering script url</dfn> (a <a for="url">URL</a>).</p>
    <p>A <a href="#dfn-service-worker-registration">service worker registration</a> has an associated <dfn id="dfn-installing-worker">installing worker</dfn> (a <a href="#dfn-service-worker">service worker</a> or null) whose <a href="#dfn-state">state</a> is <em>installing</em>. It is initially set to null.</p>
    <p>A <a href="#dfn-service-worker-registration">service worker registration</a> has an associated <dfn id="dfn-waiting-worker">waiting worker</dfn> (a <a href="#dfn-service-worker">service worker</a> or null) whose <a href="#dfn-state">state</a> is <em>installed</em>. It is initially set to null.</p>
    <p>A <a href="#dfn-service-worker-registration">service worker registration</a> has an associated <dfn id="dfn-active-worker">active worker</dfn> (a <a href="#dfn-service-worker">service worker</a> or null) whose <a href="#dfn-state">state</a> is either <em>activating</em> or <em>activated</em>. It is initially set to null.</p>
    <p>A <a href="#dfn-service-worker-registration">service worker registration</a> has an associated <dfn id="dfn-last-update-check-time">last update check time</dfn>. It is initially set to null.</p>
    <p>A <a href="#dfn-service-worker-registration">service worker registration</a> has an associated <dfn id="dfn-uninstalling-flag">uninstalling flag</dfn>. It is initially unset.</p>
    <p>A <a href="#dfn-service-worker-registration">service worker registration</a> has one or more <dfn id="dfn-service-worker-registration-task-queue">task queues</dfn> that back up the <a>tasks</a> from its <a href="#dfn-active-worker">active worker</a>'s <a>event loop</a>'s corresponding <a for="event loop">task queues</a>. (The target task sources for this back up operation are the <a href="#dfn-handle-fetch-task-source">handle fetch task source</a> and the <a href="#dfn-handle-functional-event-task-source">handle functional event task source</a>.) The user agent dumps the <a href="#dfn-active-worker">active worker</a>'s <a>tasks</a> to the <a href="#dfn-service-worker-registration">service worker registration</a>'s <a href="#dfn-service-worker-registration-task-queue">task queues</a> when the <a href="#dfn-active-worker">active worker</a> is <a href="#terminate-service-worker-algorithm">terminated</a> and <a lt="queue a task">re-queues those tasks</a> to the <a href="#dfn-active-worker">active worker</a>'s <a>event loop</a>'s corresponding <a for="event loop">task queues</a> when the <a href="#dfn-active-worker">active worker</a> spins off. Unlike the <a for="event loop">task queues</a> owned by <a>event loops</a>, the <a href="#dfn-service-worker-registration">service worker registration</a>'s <a href="#dfn-service-worker-registration-task-queue">task queues</a> are not processed by any <a>event loops</a> in and of itself.</p>

    <section>
      <h4 id="service-worker-registration-lifetime">Lifetime</h4>

      <p>A user agent <em class="rfc2119" title="MUST">must</em> persistently keep a list of <a href="#register-algorithm">registered</a> <a href="#dfn-service-worker-registration">service worker registrations</a> unless otherwise they are explicitly <a href="#unregister-algorithm">unregistered</a>. A user agent has a <a href="#dfn-scope-to-registration-map">scope to registration map</a> that stores the entries of the tuple of <a href="#dfn-service-worker-registration">service worker registration</a>'s <a href="#dfn-scope-url">scope url</a> and the corresponding <a href="#dfn-service-worker-registration">service worker registration</a>. The lifetime of <a href="#dfn-service-worker-registration">service worker registrations</a> is beyond that of the <code><a href="#service-worker-registration-interface">ServiceWorkerRegistration</a></code> objects which represent them within the lifetime of their corresponding <a href="#dfn-service-worker-client">service worker clients</a>.</p>
    </section>
  </section>

  <section dfn-for="service worker client">
    <h3 id="service-worker-client-concept">Service Worker Client</h3>
    <p>A <dfn id="dfn-service-worker-client" for="">service worker client</dfn> is a type of <a>environment settings object</a>.</p>

    <p>A <a href="#dfn-service-worker-client">service worker client</a> has an associated <dfn id="dfn-service-worker-client-active-worker">active worker</dfn> (an <a href="#dfn-active-worker">active worker</a>) which currently <a href="#dfn-control">controls</a> it. It is initially set to null.</p>

    <p>A <a href="#dfn-service-worker-client">service worker client</a> has an associated <dfn id="dfn-service-worker-client-id">id</dfn> (an opaque string), which uniquely identifies itself during its lifetime. It is initially set to a new unique value when the corresponding <a>environment settings object</a> that it represents is created.</p>

    <p>A <a href="#dfn-service-worker-client">service worker client</a> has an associated <dfn id="dfn-service-worker-client-frame-type">frame type</dfn>, which is one of <em>auxiliary</em>, <em>top-level</em>, <em>nested</em>, and <em>none</em>. Unless stated otherwise it is <em>none</em>.

    <p>A <dfn id="dfn-window-client">window client</dfn> is a <a href="#dfn-service-worker-client">service worker client</a> whose <a>global object</a> is a {{Window}} object.</p>

    <p>A <dfn id="dfn-dedicatedworker-client">dedicated worker client</dfn> is a <a href="#dfn-service-worker-client">service worker client</a> whose <a>global object</a> is a {{DedicatedWorkerGlobalScope}} object.</p>

    <p>A <dfn id="dfn-sharedworker-client">shared worker client</dfn> is a <a href="#dfn-service-worker-client">service worker client</a> whose <a>global object</a> is a {{SharedWorkerGlobalScope}} object.</p>

    <p>A <dfn id="dfn-worker-client">worker client</dfn> is either a <a href="#dfn-dedicatedworker-client">dedicated worker client</a> or a <a href="#dfn-sharedworker-client">shared worker client</a>.</p>
  </section>

  <section>
    <h3 id="selection">Selection and Use</h3>

    <p>A <a href="#dfn-service-worker-client">service worker client</a> independently <a href="#dfn-service-worker-registration-selection">selects</a> and <a href="#dfn-use">uses</a> a <a href="#dfn-service-worker-registration">service worker registration</a> for its own loading and its subresources. The <dfn id="dfn-service-worker-registration-selection">selection</dfn> of a <a href="#dfn-service-worker-registration">service worker registration</a>, upon a <a>non-subresource request</a>, is a process of either <a href="#scope-match-algorithm">matching</a> a <a href="#dfn-service-worker-registration">service worker registration</a> from <a href="#dfn-scope-to-registration-map">scope to registration map</a> or inheriting an existing <a href="#dfn-service-worker-registration">service worker registration</a> from its parent or owner context depending on the request's <a for="request">url</a>.</p>

    <p>When the request's <a for="request">url</a> is not <a lt="is local">local</a>, a <a href="#dfn-service-worker-client">service worker client</a> <a href="#scope-match-algorithm">matches</a> a <a href="#dfn-service-worker-registration">service worker registration</a> from <a href="#dfn-scope-to-registration-map">scope to registration map</a>. That is, the <a href="#dfn-service-worker-client">service worker client</a> attempts to consult a <a href="#dfn-service-worker-registration">service worker registration</a> whose <a href="#dfn-scope-url">scope url</a> <a href="#scope-match-algorithm">matches</a> its <a>creation url</a>.</p>

    <p>When the request's <a for="request">url</a> <a>is local</a>, if the <a href="#dfn-service-worker-client">service worker client</a>'s <a>responsible browsing context</a> is a <a>nested browsing context</a> or the <a href="#dfn-service-worker-client">service worker client</a> is a <a href="#dfn-worker-client">worker client</a>, the <a href="#dfn-service-worker-client">service worker client</a> inherits the <a href="#dfn-service-worker-registration">service worker registration</a> from its <a>parent browsing context</a>'s environment or one of <a>the worker's Documents</a>' environment, respectively, if it exists.</p>

    <p>If the <a href="#dfn-service-worker-registration-selection">selection</a> was successful, the <a href="#dfn-service-worker-registration-selection">selected</a> <a href="#dfn-service-worker-registration">service worker registration</a>'s <a href="#dfn-active-worker">active worker</a> starts to <dfn id="dfn-control">control</dfn> the <a href="#dfn-service-worker-client">service worker client</a>. Otherwise, the flow returns to <a>fetch</a> where it falls back to the default behavior. When a <a href="#dfn-service-worker-client">service worker client</a> is <a href="#dfn-control">controlled</a> by an <a href="#dfn-active-worker">active worker</a>, it is considered that the <a href="#dfn-service-worker-client">service worker client</a> is <dfn id="dfn-use">using</dfn> the <a href="#dfn-active-worker">active worker</a>'s <a href="#dfn-containing-service-worker-registration">containing service worker registration</a>.</p>
  </section>

  <section>
    <h3 id="task-sources">Task Sources</h3>

    <p>The following additional <a>task sources</a> are used by <a href="#dfn-service-worker">service workers</a>.</p>

    <dl>
      <dt>The <dfn id="dfn-handle-fetch-task-source">handle fetch task source</dfn></dt>
      <dd>This <a>task source</a> is used for <a>dispatching</a> <a href="#service-worker-global-scope-fetch-event">fetch</a> events to <a href="#dfn-service-worker">service workers</a>.</dd>
      <dt>The <dfn id="dfn-handle-functional-event-task-source">handle functional event task source</dfn></dt>
      <dd>This <a>task source</a> is used for features that <a>dispatch</a> other <a href="#dfn-functional-events">functional</a> events, e.g. <a href="https://w3c.github.io/push-api/#the-push-event">push</a> events, to <a href="#dfn-service-worker">service workers</a>.
        <p class="note">A user agent may use a separate task source for each functional event type in order to avoid a head-of-line blocking phenomenon for certain functional events. For instance, a user agent may use a different task source for <a href="http://web-alarms.sysapps.org/#firing-task-event-to-service-worker">task</a> events from other task sources.</p>
      </dd>
    </dl>
  </section>

  <section>
    <h3 id="user-agent-shutdown">User Agent Shutdown</h3>

    <p>A user agent <em class="rfc2119" title="MUST">must</em> maintain the state of its stored <a href="#dfn-service-worker-registration">service worker registrations</a> across restarts with the following rules:
      <ul>
        <li>An <a>installing worker</a> does not persist but discarded. If the <a>installing worker</a> was the only <a href="#dfn-service-worker">service worker</a> for the <a href="#dfn-service-worker-registration">service worker registration</a>, the <a href="#dfn-service-worker-registration">service worker registration</a> is discarded.</li>
        <li>A <a>waiting worker</a> promotes to an <a href="#dfn-active-worker">active worker</a>.</li>
      </ul>
    </p>

    <p>To attain this, the user agent <em class="rfc2119" title="MUST">must</em> invoke <a href="#on-user-agent-shutdown-algorithm">Handle User Agent Shutdown</a> when it terminates.</p>
  </section>
</section>

<section>
  <h2 id="document-context">Client Context</h2>

  <div class="example">
    Bootstrapping with a ServiceWorker:

    <pre class="lang-js">
      // scope defaults to the path the script sits in
      // "/" in this example
      navigator.serviceWorker.register("/serviceworker.js").then(
        function(registration) {
          console.log("success!");
          if (registration.installing) {
            registration.installing.postMessage("Howdy from your installing page.");
          }
        },
        function(why) {
          console.error("Installing the worker failed!:", why);
        });
    </pre>
  </div>

  <section dfn-for="ServiceWorker">
    <h3 id="service-worker-obj">{{ServiceWorker}}</h3>

    <pre class="idl">
      [SecureContext, Exposed=(Window,Worker)]
      interface ServiceWorker : EventTarget {
        readonly attribute USVString scriptURL;
        readonly attribute ServiceWorkerState state;
        void postMessage(any message, optional sequence&lt;object&gt; transfer);

        // event
        attribute EventHandler onstatechange;
      };
      ServiceWorker implements AbstractWorker;

      enum ServiceWorkerState {
        "installing",
        "installed",
        "activating",
        "activated",
        "redundant"
      };
    </pre>

    <p>A <code><dfn interface id="service-worker-interface">ServiceWorker</dfn></code> object represents a <a href="#dfn-service-worker">service worker</a>. Each {{ServiceWorker}} object is associated with a <a href="#dfn-service-worker">service worker</a>. Multiple separate objects implementing the {{ServiceWorker}} interface across documents and workers can all be associated with the same <a href="#dfn-service-worker">service worker</a> simultaneously.</p>

    <p>A {{ServiceWorker}} object has an associated {{ServiceWorkerState}} object which is itself associated with <a href="#dfn-service-worker">service worker</a>'s <a href="#dfn-state">state</a>.</p>

    <section>
      <h4 id="service-worker-url">{{ServiceWorker/scriptURL}}</h4>

      <p>The <dfn attribute id="service-worker-url-attribute"><code>scriptURL</code></dfn> attribute <em class="rfc2119" title="MUST">must</em> return the <a href="#dfn-service-worker">service worker</a>'s <a for="url">serialized</a> <a href="#dfn-script-url">script url</a>.</p>

      <div class="example">
        <p>For example, consider a document created by a navigation to <code>https://example.com/app.html</code> which <a href="#on-fetch-request-algorithm">matches</a> via the following registration call which has been previously executed:</p>

        <pre class="lang-js">
          // Script on the page https://example.com/app.html
          navigator.serviceWorker.register("/service_worker.js", { scope: "/" });
        </pre>

        <p>The value of <code>navigator.serviceWorker.controller.scriptURL</code> will be "<code>https://example.com/service_worker.js</code>".</p>
      </div>
    </section>

    <section>
      <h4 id="service-worker-state">{{ServiceWorker/state}}</h4>

      <p>The <dfn attribute id="service-worker-state-attribute"><code>state</code></dfn> attribute <em class="rfc2119" title="MUST">must</em> return the value (in <dfn enum id="service-worker-state-enum"><code>ServiceWorkerState</code></dfn> enumeration) to which it was last set.</p>
    </section>

    <section algorithm="service-worker-postmessage">
      <h4 id="service-worker-postmessage">{{ServiceWorker/postMessage(message, transfer)}}</h4>

      <p>The <dfn method id="service-worker-postmessage-method"><code>postMessage(<var>message</var>, <var>transfer</var>)</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>If the {{ServiceWorker/state}} attribute value of the <a>context object</a> is "<code>redundant</code>", <a>throw</a> an "{{InvalidStateError}}" exception and abort these steps. </li>
        <li>Let <var>serviceWorker</var> be the <a href="#dfn-service-worker">service worker</a> represented by the <a>context object</a>.</li>
        <li>Invoke <a href="#run-service-worker-algorithm">Run Service Worker</a> algorithm with <var>serviceWorker</var> as the argument.</li>
        <li>Let <var>destination</var> be the {{ServiceWorkerGlobalScope}} object associated with <var>serviceWorker</var>.</li>
        <li>Let <var>targetRealm</var> be <var>destination</var>'s <a lt="the global object's Realm">Realm</a>.</li>
        <li>Let <var>incumbentSettings</var> be the <a>incumbent settings object</a>, and <var>incumbentGlobal</var> its <a lt="the environment settings object's global object">global object</a>.</li>
        <li>Let <var>cloneRecord</var> be <a>StructuredCloneWithTransfer</a>(<var>message</var>, <var>transfer</var>, <var>targetRealm</var>). If this <a>throws</a> an exception, <a lt="throw">rethrow</a> that exception and abort these steps.</li>
        <li>Let <var>clonedMessage</var> be <var>cloneRecord</var>.\[[Clone]].</li>
        <li>Let <var>newPorts</var> be a new <a lt="frozen array type">frozen array</a> consisting of all {{MessagePort}} objects in <var>cloneRecord</var>.\[[TransferList]], if any, maintaining their relative order.</li>
        <li><a>Queue a task</a> that runs the following steps:
          <ol>
            <li>Create an event <var>e</var> that uses the {{ExtendableMessageEvent}} interface, with the event type <a href="#service-worker-global-scope-message-event">message</a>, which does not bubble and is not cancelable.</li>
            <li>Let the {{ExtendableMessageEvent/data}} attribute of <var>e</var> be initialized to <var>clonedMessage</var>.</li>
            <li>Let the {{ExtendableMessageEvent/origin}} attribute of <var>e</var> be initialized to the <a lt="unicode serialisation of an origin">Unicode serialisation</a> of <var>incumbentSettings</var>'s <a for="resource">origin</a>.</li>
            <li>If <var>incumbentGlobal</var> is a {{ServiceWorkerGlobalScope}} object, let the {{ExtendableMessageEvent/source}} attribute of <var>e</var> be initialized to a new {{ServiceWorker}} object that represents <var>incumbentGlobal</var>'s <a href="#dfn-service-worker-global-scope-service-worker">service worker</a>.</li>
            <li>Else if <var>incumbentGlobal</var> is a {{Window}} object, let the {{ExtendableMessageEvent/source}} attribute of <var>e</var> be initialized to a new {{WindowClient}} object that represents <var>incumbentGlobal</var>'s <a>browsing context</a>.</li>
            <li>Else, let it be initialized to a new {{Client}} object that represents the worker associated with <var>incumbentGlobal</var>.</li>
            <li>Let the {{ExtendableMessageEvent/ports}} attribute of <var>e</var> be initialized to <var>newPorts</var>.</li>
            <li><a>Dispatch</a> <var>e</var> at <var>destination</var>.</li>
          </ol>
          <p>The <a>task</a> <em class="rfc2119" title="MUST">must</em> use the <a>DOM manipulation task source</a>.</p>
        </li>
      </ol>
    </section>

    <section>
      <h4 id="service-worker-event-handler">Event handler</h4>

      <p>The following is the <a>event handler</a> (and its corresponding <a>event handler event type</a>) that <em class="rfc2119" title="MUST">must</em> be supported, as <a>event handler IDL attributes</a>, by all objects implementing {{ServiceWorker}} interface:</p>

      <table class="data">
        <thead>
          <tr>
            <th><a>event handler</a></th>
            <th><a>event handler event type</a></th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td><dfn attribute id="service-worker-onstatechange-attribute"><code>onstatechange</code></dfn></td>
            <td><code><a href="#service-worker-statechange-event">statechange</a></code></td>
          </tr>
        </tbody>
      </table>
    </section>
  </section>

  <section dfn-for="ServiceWorkerRegistration">
    <h3 id="service-worker-registration-obj">{{ServiceWorkerRegistration}}</h3>

    <pre class="idl">
      [SecureContext, Exposed=(Window,Worker)]
      interface ServiceWorkerRegistration : EventTarget {
        readonly attribute ServiceWorker? installing;
        readonly attribute ServiceWorker? waiting;
        readonly attribute ServiceWorker? active;

        readonly attribute USVString scope;

        [NewObject] Promise&lt;void&gt; update();
        [NewObject] Promise&lt;boolean&gt; unregister();

        // event
        attribute EventHandler onupdatefound;
      };
    </pre>

    <p>A <code><dfn interface id="service-worker-registration-interface">ServiceWorkerRegistration</dfn></code> object represents a <a href="#dfn-service-worker-registration">service worker registration</a>. Each {{ServiceWorkerRegistration}} object is associated with a <dfn id="dfn-service-worker-registration-interface-service-worker-registration">service worker registration</dfn> (a <a href="#dfn-service-worker-registration">service worker registration</a>). Multiple separate objects implementing the {{ServiceWorkerRegistration}} interface across documents and workers can all be associated with the same <a href="#dfn-service-worker-registration">service worker registration</a> simultaneously.</p>

    <section algorithm="navigator-service-worker-installing">
      <h4 id="navigator-service-worker-installing">{{ServiceWorkerRegistration/installing}}</h4>

      <p><dfn attribute id="service-worker-registration-installing-attribute"><code>installing</code></dfn> attribute <em class="rfc2119" title="MUST">must</em> return the value to which it was last set.</p>

      <p class="note">The {{ServiceWorker}} objects returned from this attribute getter that represent the same <a href="#dfn-service-worker">service worker</a> are the same objects.</p>
    </section>

    <section algorithm="navigator-service-worker-waiting">
      <h4 id="navigator-service-worker-waiting">{{ServiceWorkerRegistration/waiting}}</h4>

      <p><dfn attribute id="service-worker-registration-waiting-attribute"><code>waiting</code></dfn> attribute <em class="rfc2119" title="MUST">must</em> return the value to which it was last set.</p>

      <p class="note">The {{ServiceWorker}} objects returned from this attribute getter that represent the same <a href="#dfn-service-worker">service worker</a> are the same objects.</p>
    </section>

    <section algorithm="navigator-service-worker-active">
      <h4 id="navigator-service-worker-active">{{ServiceWorkerRegistration/active}}</h4>

      <p><dfn attribute id="service-worker-registration-active-attribute"><code>active</code></dfn> attribute <em class="rfc2119" title="MUST">must</em> return the value to which it was last set.</p>

      <p class="note">The {{ServiceWorker}} objects returned from this attribute getter that represent the same <a href="#dfn-service-worker">service worker</a> are the same objects.</p>
    </section>

    <section algorithm="service-worker-registration-scope">
      <h4 id="service-worker-registration-scope">{{ServiceWorkerRegistration/scope}}</h4>

      <p>The <dfn attribute id="service-worker-registration-scope-attribute"><code>scope</code></dfn> attribute <em class="rfc2119" title="MUST">must</em> return <a href="#dfn-service-worker-registration-interface-service-worker-registration">service worker registration</a>'s <a for="url">serialized</a> <a href="#dfn-scope-url">scope url</a>.</p>

      <p class="example">In the example in section 3.1.1, the value of <code>registration.scope</code>, obtained from <code>navigator.serviceWorker.ready.then(function(registration) { console.log(registration.scope); })</code> for example, will be "<code>https://example.com/</code>".</p>
    </section>

    <section algorithm="service-worker-registration-update">
      <h4 id="service-worker-registration-update">{{ServiceWorkerRegistration/update()}}</h4>

      <p><dfn method id="service-worker-registration-update-method"><code>update()</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>Let <var>p</var> be a <a>promise</a>.</li>
        <li>Let <var>registration</var> be the <a href="#dfn-service-worker-registration-interface-service-worker-registration">service worker registration</a>.</li>
        <li>Let <var>newestWorker</var> be the result of running <a href="#get-newest-worker-algorithm">Get Newest Worker</a> algorithm passing <var>registration</var> as its argument.</li>
        <li>If <var>newestWorker</var> is null, reject <var>p</var> with an "{{InvalidStateError}}" exception and abort these steps.</li>
        <li>If the <a>context object</a>'s <a>relevant settings object</a>'s <a>global object</a> <var>globalObject</var> is a {{ServiceWorkerGlobalScope}} object, and <var>globalObject</var>'s associated <a href="#dfn-service-worker-global-scope-service-worker">service worker</a>'s <a href="#dfn-state">state</a> is <em>installing</em>, reject <var>p</var> with an "{{InvalidStateError}}" exception and abort these steps.</li>
        <li>Let <var>job</var> be the result of running <a href="#create-job-algorithm">Create Job</a> with <em>update</em>, <var>registration</var>'s <a href="#dfn-scope-url">scope url</a>, <var>newestWorker</var>'s <a href="#dfn-script-url">script url</a>, <var>p</var>, and the <a>context object</a>'s <a>relevant settings object</a> <var>client</var>.</li>
        <li>Set <var>job</var>'s <a>worker type</a> to <var>newestWorker</var>'s <a for="service worker">type</a>.</li>
        <li>Invoke <a href="#schedule-job-algorithm">Schedule Job</a> with <var>job</var>.</li>
        <li>Return <var>p</var>.</li>
      </ol>
    </section>

    <section algorithm="navigator-service-worker-unregister">
      <h4 id="navigator-service-worker-unregister">{{ServiceWorkerRegistration/unregister()}}</h4>

      <p class="note">The {{ServiceWorkerRegistration/unregister()}} method unregisters the <a href="#dfn-service-worker-registration">service worker registration</a>. It is important to note that the currently <a href="#dfn-control">controlled</a> <a href="#dfn-service-worker-client">service worker client</a>'s <a href="#dfn-service-worker-client-active-worker">active worker</a>'s <a href="#dfn-containing-service-worker-registration">containing service worker registration</a> is effective until all the <a href="#dfn-service-worker-client">service worker clients</a> (including itself) using this <a href="#dfn-service-worker-registration">service worker registration</a> unload. That is, the {{ServiceWorkerRegistration/unregister()}} method only affects subsequent <a lt="navigate">navigations</a>.</p>

      <p><dfn method id="service-worker-registration-unregister-method"><code>unregister()</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>Let <var>p</var> be a <a>promise</a>.</li>
        <li>Let <var>job</var> be the result of running <a href="#create-job-algorithm">Create Job</a> with <em>unregister</em>, the <a href="#dfn-scope-url">scope url</a> of the <a href="#dfn-service-worker-registration-interface-service-worker-registration">service worker registration</a>, null, <var>p</var>, and the <a>context object</a>'s <a>relevant settings object</a> <var>client</var>.</li>
        <li>Invoke <a href="#schedule-job-algorithm">Schedule Job</a> with <var>job</var>.</li>
        <li>Return <var>p</var>.</li>
      </ol>
    </section>

    <section>
      <h4 id="service-worker-registration-event-handler">Event handler</h4>

      <p>The following is the <a>event handler</a> (and its corresponding <a>event handler event type</a>) that <em class="rfc2119" title="MUST">must</em> be supported, as <a>event handler IDL attributes</a>, by all objects implementing <code><a href="#service-worker-registration-interface">ServiceWorkerRegistration</a></code> interface:</p>

      <table class="data">
        <thead>
          <tr>
            <th><a>event handler</a></th>
            <th><a>event handler event type</a></th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td><dfn attribute id="service-worker-registration-onupdatefound-attribute"><code>onupdatefound</code></dfn></td>
            <td><code><a href="#service-worker-registration-updatefound-event">updatefound</a></code></td>
          </tr>
        </tbody>
      </table>
    </section>
  </section>

  <section>
    <h3 id="navigator-service-worker">{{Navigator/serviceWorker|navigator.serviceWorker}}</h3>

    <pre class="idl">
      partial interface Navigator {
        [SecureContext, SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
      };

      partial interface WorkerNavigator {
        [SecureContext, SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
      };
    </pre>

    <p>The <dfn attribute for="Navigator,WorkerNavigator" id="navigator-service-worker-attribute"><code>serviceWorker</code></dfn> attribute <em class="rfc2119" title="MUST">must</em> return the {{ServiceWorkerContainer}} object that is associated with the <a>context object</a>.</p>
  </section>

  <section dfn-for="ServiceWorkerContainer">
    <h3 id="service-worker-container">{{ServiceWorkerContainer}}</h3>

    <pre class="idl">
      [SecureContext, Exposed=(Window,Worker)]
      interface ServiceWorkerContainer : EventTarget {
        readonly attribute ServiceWorker? controller;
        [SameObject] readonly attribute Promise&lt;ServiceWorkerRegistration&gt; ready;

        [NewObject] Promise&lt;ServiceWorkerRegistration&gt; register(USVString scriptURL, optional RegistrationOptions options);

        [NewObject] Promise&lt;any&gt; getRegistration(optional USVString clientURL = "");
        [NewObject] Promise&lt;sequence&lt;ServiceWorkerRegistration&gt;&gt; getRegistrations();

        void startMessages();


        // events
        attribute EventHandler oncontrollerchange;
        attribute EventHandler onmessage; // event.source of message events is ServiceWorker object
      };
    </pre>
    <pre class="idl" id="registration-option-list-dictionary">
      dictionary RegistrationOptions {
        USVString scope;
        WorkerType type = "classic";
      };
    </pre>

  <p>The user agent <em class="rfc2119" title="MUST">must</em> create a {{ServiceWorkerContainer}} object when a {{Navigator}} object or a {{WorkerNavigator}} object is created and associate it with that object.</p>

  <p>A <code><dfn interface id="service-worker-container-interface">ServiceWorkerContainer</dfn></code> provides capabilities to register, unregister, and update the <a href="#dfn-service-worker-registration">service worker registrations</a>, and provides access to the state of the <a href="#dfn-service-worker-registration">service worker registrations</a> and their associated <a href="#dfn-service-worker">service workers</a>.</p>

  <p>A {{ServiceWorkerContainer}} has an associated <dfn id="dfn-service-worker-container-interface-client" for=ServiceWorkerContainer>service worker client</dfn>, which is a <a href="#dfn-service-worker-client">service worker client</a> whose <a>global object</a> is associated with the {{Navigator}} object or the {{WorkerNavigator}} object that the {{ServiceWorkerContainer}} is retrieved from.</p>

  <p>A {{ServiceWorkerContainer}} object has an associated <dfn id="dfn-ready-promise">ready promise</dfn> (a <a>promise</a>). It is initially set to a new <a>promise</a>.</p>

  <p>A {{ServiceWorkerContainer}} object has a <a>task source</a> called the <dfn id="dfn-client-message-queue">client message queue</dfn>, initially empty. A <a>client message queue</a> can be enabled or disabled, and is initially disabled. When a {{ServiceWorkerContainer}} object's <a>client message queue</a> is enabled, the <a>event loop</a> <em class="rfc2119" title="MUST">must</em> use it as one of its <a>task sources</a>. When the {{ServiceWorkerContainer}} object's <a>relevant global object</a> is a {{Window}} object, all <a>tasks</a> <a lt="queue a task">queued</a> on its <a>client message queue</a> <em class="rfc2119" title="MUST">must</em> be associated with its <a>relevant settings object</a>'s <a>responsible document</a>.</p>

    <section algorithm="navigator-service-worker-controller">
      <h4 id="navigator-service-worker-controller">{{ServiceWorkerContainer/controller}}</h4>

      <p><dfn attribute id="service-worker-container-controller-attribute"><code>controller</code></dfn> attribute <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>Let <var>client</var> be the <a>context object</a>'s <a href="#dfn-service-worker-container-interface-client">service worker client</a>.</li>
        <li>Return the {{ServiceWorker}} object that represents <var>client</var>'s <a href="#dfn-service-worker-client-active-worker">active worker</a>.</li>
      </ol>

      <p class="note">{{ServiceWorkerContainer/controller|navigator.serviceWorker.controller}} returns <code>null</code> if the request is a force refresh (shift+refresh). The {{ServiceWorker}} objects returned from this attribute getter that represent the same <a href="#dfn-service-worker">service worker</a> are the same objects.</p>

      </section>

      <section algorithm="navigator-service-worker-ready">
        <h4 id="navigator-service-worker-ready">{{ServiceWorkerContainer/ready}}</h4>

      <p><dfn attribute id="service-worker-container-ready-attribute"><code>ready</code></dfn> attribute <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>If the <a>context object</a>'s <a href="#dfn-ready-promise">ready promise</a> is settled, return the <a>context object</a>'s <a href="#dfn-ready-promise">ready promise</a>.</li>
        <li>Let <var>client</var> be the <a>context object</a>'s <a href="#dfn-service-worker-container-interface-client">service worker client</a>.</li>
        <li>Let <var>registration</var> be null.</li>
        <li>Let <var>clientURL</var> be <var>client</var>'s <a>creation url</a>.</li>
        <li>Run the following substeps <a>in parallel</a>:
          <ol>
            <li><em>CheckRegistration</em>: If the result of running <a href="#scope-match-algorithm">Match Service Worker Registration</a> algorithm with <var>clientURL</var> as its argument is not null, then:
              <ol>
                <li>Set <var>registration</var> to the result value.</li>
              </ol>
            </li>
            <li>Else:
              <ol>
                <li>Wait until <a href="#dfn-scope-to-registration-map">scope to registration map</a> has a new entry.</li>
                <li>Jump to the step labeled <em>CheckRegistration</em>.</li>
              </ol>
            </li>
            <li>If <var>registration</var>'s <a href="#dfn-active-worker">active worker</a> is null, wait until <var>registration</var>'s <a href="#dfn-active-worker">active worker</a> changes.
              <p class="note">Implementers should consider this condition is met when the corresponding registration request gets to the step 6 of <a href="#activation-algorithm">Activate</a> algorithm.</p>
            </li>
            <li>Resolve <a>context object</a>'s <a href="#dfn-ready-promise">ready promise</a> with the {{ServiceWorkerRegistration}} object which represents <var>registration</var>.</li>
          </ol>
        </li>
        <li>Return <a>context object</a>'s <a href="#dfn-ready-promise">ready promise</a>.</li>
      </ol>

      <p class="note">When the <code><a href="#service-worker-container-ready-attribute">ready</a></code> attribute is accessed, the returned <a>promise</a> will never reject. Instead, it waits until the <a>promise</a> resolves with a <a href="#dfn-service-worker-registration">service worker registration</a> that has an <a href="#dfn-active-worker">active worker</a>.</p>
    </section>

    <section algorithm="navigator-service-worker-register">
      <h4 id="navigator-service-worker-register">{{ServiceWorkerContainer/register(scriptURL, options)}}</h4>

      <p class="note">The {{ServiceWorkerContainer/register(scriptURL, options)}} method creates or updates a <a href="#dfn-service-worker-registration">service worker registration</a> for the given <a href="#dfn-scope-url">scope url</a>. If successful, a <a href="#dfn-service-worker-registration">service worker registration</a> ties the provided <var>scriptURL</var> to a <a href="#dfn-scope-url">scope url</a>, which is subsequently used for <a href="#on-fetch-request-algorithm">navigation matching</a>.</p>

      <p><dfn method id="service-worker-container-register-method"><code>register(<var>scriptURL</var>, <var>options</var>)</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>Let <var>p</var> be a <a>promise</a>.</li>
        <li>Let <var>client</var> be the <a>context object</a>'s <a href="#dfn-service-worker-container-interface-client">service worker client</a>.</li>
        <li>Let <var>scriptURL</var> be the result of <a for="url">parsing</a> <var>scriptURL</var> with <a>entry settings object</a>'s <a>API base URL</a>.</li>
        <li>Let <var>scopeURL</var> be null.</li>
        <li>If <var>options</var>.{{RegistrationOptions/scope}} is <a>present</a>, set <var>scopeURL</var> to <var>options</var>.{{RegistrationOptions/scope}}.</li>
        <li>Invoke [[#start-register-algorithm]] with <var>scopeURL</var>, <var>scriptURL</var>, <var>p</var>, <var>client</var>, <var>client</var>'s <a>creation URL</a> and <var>options</var>.{{RegistrationOptions/type}}.</li>
        <li>Return <var>p</var>.</li>
      </ol>
    </section>

    <section algorithm="navigator-service-worker-getRegistration">
      <h4 id="navigator-service-worker-getRegistration">{{ServiceWorkerContainer/getRegistration(clientURL)}}</h4>

      <p><dfn method id="service-worker-container-getregistration-method"><code>getRegistration(<var>clientURL</var>)</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>Let <var>client</var> be the <a>context object</a>'s <a href="#dfn-service-worker-container-interface-client">service worker client</a>.</li>
        <li>Let <var>clientURL</var> be the result of <a for="url">parsing</a> <var>clientURL</var> with <a>entry settings object</a>'s <a>API base URL</a>.</li>
        <li>If <var>clientURL</var> is failure, return a <a>promise</a> rejected with a <code>TypeError</code>.</li>
        <li>If the <a for="resource">origin</a> of <var>clientURL</var> is not <var>client</var>'s <a for="resource">origin</a>, return a <var>promise</var> rejected with a "{{SecurityError}}" exception.</li>
        <li>Let <var>promise</var> be a new <a>promise</a>.</li>
        <li>Run the following substeps <a>in parallel</a>:
          <ol>
            <li>Let <var>registration</var> be the result of running <a href="#scope-match-algorithm">Match Service Worker Registration</a> algorithm with <var>clientURL</var> as its argument.</li>
            <li>If <var>registration</var> is not null, then:
              <ol>
                <li>Resolve <var>promise</var> with the {{ServiceWorkerRegistration}} object which represents <var>registration</var>.</li>
              </ol>
            </li>
            <li>Else:
              <ol>
                <li>Resolve <var>promise</var> with undefined.</li>
              </ol>
            </li>
          </ol>
        </li>
        <li>Return <var>promise</var>.</li>
      </ol>
    </section>

    <section algorithm="navigator-service-worker-getRegistrations">
      <h4 id="navigator-service-worker-getRegistrations">{{ServiceWorkerContainer/getRegistrations()}}</h4>

      <p><dfn method id="service-worker-container-getregistrations-method"><code>getRegistrations()</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>Let <var>client</var> be the <a>context object</a>'s <a href="#dfn-service-worker-container-interface-client">service worker client</a>.</li>
        <li>Let <var>promise</var> be a new <a>promise</a>.</li>
        <li>Run the following substeps <a>in parallel</a>:
          <ol>
            <li>Let <var>array</var> be an empty array.</li>
            <li>For each <a>Record</a> {\[[key]], \[[value]]} <var>entry</var> of <a href="#dfn-scope-to-registration-map">scope to registration map</a>:
              <ol>
                <li>If the <a for="resource">origin</a> of the result of <a for="url">parsing</a> <var>entry</var>.\[[key]] is the <a lt="same origin">same</a> as <var>client</var>'s <a for="resource">origin</a>, and <var>entry</var>.\[[value]]'s <a href="#dfn-uninstalling-flag">uninstalling flag</a> is unset, add the {{ServiceWorkerRegistration}} object associated with <var>entry</var>.\[[value]] to the <var>array</var>.</li>
              </ol>
            </li>
            <li>Resolve <var>promise</var> with <var>array</var>.</li>
          </ol>
        </li>
        <li>Return <var>promise</var>.</li>
      </ol>
    </section>

    <section algorithm="navigator-service-worker-startMessages">
      <h4 id="navigator-service-worker-startMessages">{{ServiceWorkerContainer/startMessages()}}</h4>

      <p><dfn method id="service-worker-container-startMessages-method"><code>startMessages()</code></dfn> method <em class="rfc2119" title="MUST">must</em> enable the <a>context object</a>'s <a>client message queue</a> if it is not enabled.</p>
    </section>

    <section>
      <h4 id="service-worker-container-event-handlers">Event handlers</h4>

      <p>The following are the <a>event handlers</a> (and their corresponding <a>event handler event types</a>) that <em class="rfc2119" title="MUST">must</em> be supported, as <a>event handler IDL attributes</a>, by all objects implementing the <a href="#service-worker-container-interface">ServiceWorkerContainer</a> interface:</p>

      <table class="data">
        <thead>
          <tr>
            <th><a>event handler</a></th>
            <th><a>event handler event type</a></th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td><dfn attribute id="service-worker-container-oncontrollerchange-attribute"><code>oncontrollerchange</code></dfn></td>
            <td><code><a href="#service-worker-container-controllerchange-event">controllerchange</a></code></td>
          </tr>
          <tr>
            <td><dfn attribute id="service-worker-container-onmessage-attribute"><code>onmessage</code></dfn></td>
            <td><code><a href="#service-worker-container-message-event">message</a></code></td>
          </tr>
        </tbody>
      </table>

      <p>The first time the <a>context object</a>'s <a href="#service-worker-container-onmessage-attribute">onmessage</a> IDL attribute is set, its <a>client message queue</a> <em class="rfc2119" title="MUST">must</em> be enabled.</p>
    </section>
  </section>

  <section dfn-for="ServiceWorkerMessageEvent">
    <h3 id="serviceworkermessage-event-section">{{ServiceWorkerMessageEvent}}</h3>

    <pre class="idl">
      [Constructor(DOMString type, optional ServiceWorkerMessageEventInit eventInitDict), Exposed=(Window,Worker)]
      interface ServiceWorkerMessageEvent : Event {
        readonly attribute any data;
        readonly attribute DOMString origin;
        readonly attribute DOMString lastEventId;
        [SameObject] readonly attribute (ServiceWorker or MessagePort)? source;
        readonly attribute FrozenArray&lt;MessagePort&gt;? ports;
      };
    </pre>
    <pre class="idl" id="serviceworkermessage-event-init-dictionary">
      dictionary ServiceWorkerMessageEventInit : EventInit {
        any data;
        DOMString origin;
        DOMString lastEventId;
        (ServiceWorker or MessagePort)? source;
        sequence&lt;MessagePort&gt;? ports;
      };
    </pre>

    <p><a href="#dfn-service-worker">Service workers</a> define the <a href="#service-worker-container-message-event">message</a> event that extends the {{Window/message}} event defined in [[!HTML]] to allow setting a {{ServiceWorker}} object as the source of the message. For the <a href="#service-worker-container-message-event">message</a> event, <a href="#dfn-service-worker">service workers</a> use the <code><dfn interface id="serviceworkermessage-event-interface">ServiceWorkerMessageEvent</dfn></code> interface.</p>

    <section>
      <h4 id="serviceworkermessage-event-data">{{ServiceWorkerMessageEvent/data|event.data}}</h4>

      <p>The <dfn attribute id="serviceworkermessage-event-data-attribute">data</dfn> attribute <em class="rfc2119" title="MUST">must</em> return the value it was initialized to. When the object is created, this attribute <em class="rfc2119" title="MUST">must</em> be initialized to null. It represents the message being sent.</p>
    </section>

    <section>
      <h4 id="serviceworkermessage-event-origin">{{ServiceWorkerMessageEvent/origin|event.origin}}</h4>

      <p>The <dfn attribute id="serviceworkermessage-event-origin-attribute">origin</dfn> attribute <em class="rfc2119" title="MUST">must</em> return the value it was initialized to. When the object is created, this attribute <em class="rfc2119" title="MUST">must</em> be initialized to the empty string. It represents the <a for="resource">origin</a> of the <a href="#dfn-service-worker">service worker</a>'s <a>environment settings object</a> from which the message is sent.</p>
    </section>

    <section>
      <h4 id="serviceworkermessage-event-lasteventid">{{ServiceWorkerMessageEvent/lastEventId|event.lastEventId}}</h4>

      <p>The <dfn attribute id="serviceworkermessage-event-lasteventid-attribute">lastEventId</dfn> attribute <em class="rfc2119" title="MUST">must</em> return the value it was initialized to. When the object is created, this attribute <em class="rfc2119" title="MUST">must</em> be initialized to the empty string.</p>
    </section>

    <section>
      <h4 id="serviceworkermessage-event-source">{{ServiceWorkerMessageEvent/source|event.source}}</h4>

      <p>The <dfn attribute id="serviceworkermessage-event-source-attribute">source</dfn> attribute <em class="rfc2119" title="MUST">must</em> return the value it was initialized to. When the object is created, this attribute <em class="rfc2119" title="MUST">must</em> be initialized to null. It represents the <code><a href="#service-worker-interface">ServiceWorker</a></code> object whose associated <a href="#dfn-service-worker">service worker</a> the message is sent from.</p>
    </section>

    <section>
      <h4 id="serviceworkermessage-event-ports">{{ServiceWorkerMessageEvent/ports|event.ports}}</h4>

      <p>The <dfn attribute id="serviceworkermessage-event-ports-attribute">ports</dfn> attribute <em class="rfc2119" title="MUST">must</em> return the value it was initialized to. When the object is created, this attribute <em class="rfc2119" title="MUST">must</em> be initialized to null. It represents the {{MessagePort}} array being sent, if any.</p>
    </section>
  </section>

  <section>
    <h3 id="document-context-events">Events</h3>

    <p>The following event is dispatched on {{ServiceWorker}} object:</p>

    <table class="data">
      <thead>
        <tr>
          <th>Event name</th>
          <th>Interface</th>
          <th>Dispatched when&mldr;</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><dfn event for="ServiceWorker" id="service-worker-statechange-event"><code>statechange</code></dfn></td>
          <td>{{Event}}</td>
          <td>The {{ServiceWorker/state}} attribute of the {{ServiceWorker}} object is changed.</td>
        </tr>
      </tbody>
    </table>

    <p>The following event is dispatched on {{ServiceWorkerRegistration}} object:</p>

    <table class="data">
      <thead>
        <tr>
          <th>Event name</th>
          <th>Interface</th>
          <th>Dispatched when&mldr;</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><dfn event for="ServiceWorkerRegistration" id="service-worker-registration-updatefound-event"><code>updatefound</code></dfn></td>
          <td>{{Event}}</td>
          <td>The <a href="#dfn-service-worker-registration-interface-service-worker-registration">service worker registration</a>'s <a href="#dfn-installing-worker">installing worker</a> changes. (See step 8 of the <a href="#installation-algorithm">Install</a> algorithm.)</td>
        </tr>
      </tbody>
    </table>

    <p>The following events are dispatched on {{ServiceWorkerContainer}} object:</p>

    <table class="data" dfn-for="ServiceWorkerContainer">
      <thead>
        <tr>
          <th>Event name</th>
          <th>Interface</th>
          <th>Dispatched when&mldr;</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><dfn event id="service-worker-container-controllerchange-event"><code>controllerchange</code></dfn></td>
          <td>{{Event}}</td>
          <td>The <a href="#dfn-service-worker-container-interface-client">service worker client</a>'s <a href="#dfn-service-worker-client-active-worker">active worker</a> changes. (See step 9.2 of the <a href="#activation-algorithm">Activate</a> algorithm. The <a href="#dfn-skip-waiting-flag">skip waiting flag</a> of a <a href="#dfn-service-worker">service worker</a> causes <a href="#activation-algorithm">activation</a> of the <a href="#dfn-service-worker-registration">service worker registration</a> to occur while <a href="#dfn-service-worker-client">service worker clients</a> are <a href="#dfn-use">using</a> the <a href="#dfn-service-worker-registration">service worker registration</a>, {{ServiceWorkerContainer/controller|navigator.serviceWorker.controller}} immediately reflects the <a href="#dfn-active-worker">active worker</a> as the <a href="#dfn-service-worker">service worker</a> that <a href="#dfn-control">controls</a> the <a href="#dfn-service-worker-client">service worker client</a>.)</td>
        </tr>
        <tr>
          <td><dfn event id="service-worker-container-message-event"><code>message</code></dfn></td>
          <td>{{ServiceWorkerMessageEvent}}</td>
          <td>When it receives a message.</td>
        </tr>
      </tbody>
    </table>
  </section>
</section>

<section>
  <h2 id="execution-context">Execution Context</h2>

  <div class="example">
    Serving Cached Resources:

    <pre class="lang-js">
      // caching.js
      this.addEventListener("install", function(e) {
        e.waitUntil(
          // Open a cache of resources.
          caches.open("shell-v1").then(function(cache) {
            // Begins the process of fetching them.
            // The coast is only clear when all the resources are ready.
            return cache.addAll([
              "/app.html",
              "/assets/v1/base.css",
              "/assets/v1/app.js",
              "/assets/v1/logo.png",
              "/assets/v1/intro_video.webm"
            ]);
          })
        );
      });

      this.addEventListener("fetch", function(e) {
        // No "fetch" events are dispatched to the service worker until it
        // successfully installs and activates.

        // All operations on caches are async, including matching URLs, so we use
        // promises heavily. e.respondWith() even takes promises to enable this:
        e.respondWith(
          caches.match(e.request).then(function(response) {
            return response || fetch(e.request);
          }).catch(function() {
            return caches.match("/fallback.html");
          })
        );
      });
    </pre>
  </div>

  <section dfn-for="ServiceWorkerGlobalScope">
    <h3 id="service-worker-global-scope">{{ServiceWorkerGlobalScope}}</h3>

    <pre class="idl">
      [Global=(Worker,ServiceWorker), Exposed=ServiceWorker]
      interface ServiceWorkerGlobalScope : WorkerGlobalScope {
        // A container for a list of Client objects that correspond to
        // browsing contexts (or shared workers) that are on the origin of this SW
        [SameObject] readonly attribute Clients clients;
        [SameObject] readonly attribute ServiceWorkerRegistration registration;

        [NewObject] Promise&lt;void&gt; skipWaiting();

        attribute EventHandler oninstall;
        attribute EventHandler onactivate;
        attribute EventHandler onfetch;
        attribute EventHandler onforeignfetch;

        // event
        attribute EventHandler onmessage; // event.source of the message events is Client object
      };
    </pre>

    <p>A <code><dfn interface id="service-worker-global-scope-interface">ServiceWorkerGlobalScope</a></code> object represents the global execution context of a <a href="#dfn-service-worker">service worker</a>. A {{ServiceWorkerGlobalScope}} object has an associated <dfn id="dfn-service-worker-global-scope-service-worker">service worker</dfn> (a <a href="#dfn-service-worker">service worker</a>).</p>

    <p class="note">{{ServiceWorkerGlobalScope}} object provides generic, event-driven, time-limited script execution contexts that run at an origin. Once successfully <a href="#navigator-service-worker-register">registered</a>, a <a href="#dfn-service-worker">service worker</a> is started, kept alive and killed by their relationship to events, not <a href="#dfn-service-worker-client">service worker clients</a>. Any type of synchronous requests must not be initiated inside of a <a href="#dfn-service-worker">service worker</a>.</p>

    <section>
      <h4 id="service-worker-global-scope-clients">{{ServiceWorkerGlobalScope/clients}}</h4>

      <p><dfn attribute id="service-worker-global-scope-clients-attribute"><code>clients</code></dfn> attribute <em class="rfc2119" title="MUST">must</em> return the {{Clients}} object that is associated with the <a>context object</a>.</p>
    </section>

    <section>
      <h4 id="service-worker-global-scope-registration">{{ServiceWorkerGlobalScope/registration}}</h4>

      <p>The <dfn attribute id="service-worker-global-scope-scope-attribute"><code>registration</code></dfn> attribute <em class="rfc2119" title="MUST">must</em> return the {{ServiceWorkerRegistration}} object that represents the <a href="#dfn-service-worker-global-scope-service-worker">service worker</a>'s <a href="#dfn-containing-service-worker-registration">containing service worker registration</a>.</p>
    </section>

    <section algorithm="service-worker-global-scope-skipwaiting">
      <h4 id="service-worker-global-scope-skipwaiting">{{ServiceWorkerGlobalScope/skipWaiting()}}</h4>

      <p class="note">The {{ServiceWorkerGlobalScope/skipWaiting()}} method allows this <a href="#dfn-service-worker">service worker</a> to progress from the <a href="#dfn-containing-service-worker-registration">registration</a>'s <a href="#dfn-waiting-worker">waiting</a> position to <a href="#dfn-active-worker">active</a> even while <a href="#service-worker-client-concept">service worker clients</a> are <a href="#dfn-use">using</a> the <a href="#dfn-containing-service-worker-registration">registration</a>.</p>

      <p><dfn method id="service-worker-global-scope-skipwaiting-method"><code>skipWaiting()</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>Let <var>promise</var> be a new <a>promise</a>.</li>
        <li>Run the following substeps <a>in parallel</a>:
          <ol>
            <li>Set <a href="#dfn-service-worker">service worker</a>'s <a href="#dfn-skip-waiting-flag">skip waiting flag</a></li>
            <li>If <a href="#dfn-service-worker">service worker</a>'s <a href="#dfn-state">state</a> is <em>installed</em>, then:
              <ol>
                <li>Run <a href="#activation-algorithm">Activate</a> algorithm passing <a href="#dfn-service-worker">service worker</a>'s <a href="#dfn-containing-service-worker-registration">registration</a> as the argument.</li>
              </ol>
            </li>
            <li>Resolve <var>promise</var> with undefined.</li>
          </ol>
        </li>
        <li>Return <var>promise</var>.</li>
      </ol>
    </section>

    <section>
      <h4 id="service-worker-global-scope-event-handlers">Event handlers</h4>

      <p>The following are the <a>event handlers</a> (and their corresponding <a>event handler event types</a>) that <em class="rfc2119" title="MUST">must</em> be supported, as <a>event handler IDL attributes</a>, by all objects implementing the <a href="#service-worker-global-scope-interface">ServiceWorkerGlobalScope</a> interface:</p>

      <table class="data">
        <thead>
          <tr>
            <th><a>event handler</a></th>
            <th><a>event handler event type</a></th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td><dfn attribute id="service-worker-global-scope-oninstall-attribute"><code>oninstall</code></dfn></td>
            <td><code><a href="#service-worker-global-scope-install-event">install</a></code></td>
          </tr>
          <tr>
            <td><dfn attribute id="service-worker-global-scope-onactivate-attribute"><code>onactivate</code></dfn></td>
            <td><code><a href="#service-worker-global-scope-activate-event">activate</a></code></td>
          </tr>
          <tr>
            <td><dfn attribute id="service-worker-global-scope-onfetch-attribute"><code>onfetch</code></dfn></td>
            <td><code><a href="#service-worker-global-scope-fetch-event">fetch</a></code></td>
          </tr>
          <tr>
            <td><dfn attribute><code>onforeignfetch</code></dfn></td>
            <td><code><a href="#service-worker-global-scope-foreignfetch-event">foreignfetch</a></code></td>
          </tr>
          <tr>
            <td><dfn attribute id="service-worker-global-scope-onmessage-attribute"><code>onmessage</code></dfn></td>
            <td><code><a href="#service-worker-global-scope-message-event">message</a></code></td>
          </tr>
        </tbody>
      </table>
    </section>
  </section>

  <section>
    <h3 id="client">{{Client}}</h3>

    <pre class="idl">
      [Exposed=ServiceWorker]
      interface Client {
        readonly attribute USVString url;
        readonly attribute FrameType frameType;
        readonly attribute DOMString id;
        void postMessage(any message, optional sequence&lt;object&gt; transfer);
      };

      [Exposed=ServiceWorker]
      interface WindowClient : Client {
        readonly attribute VisibilityState visibilityState;
        readonly attribute boolean focused;
        [NewObject] Promise&lt;WindowClient&gt; focus();
        [NewObject] Promise&lt;WindowClient&gt; navigate(USVString url);
      };

      enum FrameType {
        "auxiliary",
        "top-level",
        "nested",
        "none"
      };
    </pre>

    <p>A <code><dfn interface id="client-interface">Client</dfn></code> object has an associated <dfn id="dfn-service-worker-client-client" for=Client>service worker client</dfn> (a <a href="#dfn-service-worker-client">service worker client</a>).</p>

    <p>A <code><dfn interface id="window-client-interface">WindowClient</dfn></code> object has an associated <dfn id="dfn-service-worker-client-visibilitystate">visibility state</dfn>, which is one of {{Document/visibilityState}} attribute value.</p>

    <p>A {{WindowClient}} object has an associated <dfn id="dfn-service-worker-client-focusstate">focus state</dfn>, which is either true or false (initially false).</p>

    <section>
      <h4 id="client-url">{{Client/url}}</h4>

      <p>The <dfn attribute for="Client" id="client-url-attribute"><code>url</code></dfn> attribute <em class="rfc2119" title="MUST">must</em> return the <a>context object</a>'s associated <a href="#dfn-service-worker-client-client">service worker client</a>'s <a for="url">serialized</a> <a>creation url</a>.</p>
    </section>

    <section>
      <h4 id="client-frametype">{{Client/frameType}}</h4>

      <p>The <dfn attribute for="Client" id="client-frametype-attribute"><code>frameType</code></dfn> attribute <em class="rfc2119" title="MUST">must</em> return the value (in <dfn enum id="contextframetype-enum"><code>FrameType</code></dfn> enumeration) corresponding to the first matching statement, switching on <a href="#dfn-service-worker-client-client">service worker client</a>'s <a href="#dfn-service-worker-client-frame-type">frame type</a>:</p>

      <dl>
        <dt><em>auxiliary</em></dt>
        <dd>"<code>auxiliary</code>"
        <p class="note">The <a href="#dfn-window-client">window client</a>'s <a>global object</a>'s <a>browsing context</a> is an <a>auxiliary browsing context</a>.</p></dd>

        <dt><em>top-level</em></dt>
        <dd>"<code>top-level</code>"
        <p class="note">The <a href="#dfn-window-client">window client</a>'s <a>global object</a>'s <a>browsing context</a> is a <a>top-level browsing context</a>.</p></dd>

        <dt><em>nested</em></dt>
        <dd>"<code>nested</code>"
        <p class="note">The <a href="#dfn-window-client">window client</a>'s <a>global object</a>'s <a>browsing context</a> is a <a>nested browsing context</a>.</p></dd>

        <dt><em>none</em></dt>
        <dd>"<code>none</code>"</dd>
      </dl>
    </section>

    <section>
      <h4 id="client-id">{{Client/id}}</h4>

      <p>The <dfn attribute for="Client" id="client-id-attribute"><code>id</code></dfn> attribute <em class="rfc2119" title="MUST">must</em> return its associated <a href="#dfn-service-worker-client-client">service worker client</a>'s <a href="#dfn-service-worker-client-id">id</a>.</p>
    </section>

    <section algorithm="client-postmessage">
      <h4 id="client-postmessage">{{Client/postMessage(message, transfer)}}</h4>

      <p>The <dfn method for="Client" id="client-postmessage-method"><code>postMessage(<var>message</var>, <var>transfer</var>)</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>Let <var>sourceSettings</var> be the <a>context object</a>'s <a>relevant settings object</a>.</li>
        <li>Let <var>destination</var> be the {{ServiceWorkerContainer}} object whose <a href="#dfn-service-worker-container-interface-client">service worker client</a> is the <a>context object</a>'s <a href="#dfn-service-worker-client-client">service worker client</a>.</li>
        <li>If <var>destination</var> is null, <a>throw</a> an "{{InvalidStateError}}" exception.</li>
        <li>Let <var>targetRealm</var> be <var>destination</var>'s <a>relevant Realm</a>.</li>
        <li>Let <var>cloneRecord</var> be <a>StructuredCloneWithTransfer</a>(<var>message</var>, <var>transfer</var>, <var>targetRealm</var>). If this <a>throws</a> an exception, <a lt="throw">rethrow</a> that exception and abort these steps.</li>
        <li>Let <var>clonedMessage</var> be <var>cloneRecord</var>.\[[Clone]].</li>
        <li>Let <var>newPorts</var> be a new <a lt="frozen array type">frozen array</a> consisting of all {{MessagePort}} objects in <var>cloneRecord</var>.\[[TransferList]], if any, maintaining their relative order.</li>
        <li>Add a <a>task</a> that runs the following steps to <var>destination</var>'s <a>client message queue</a>:
          <ol>
            <li>Create an event <var>e</var> that uses the {{ServiceWorkerMessageEvent}} interface, with the event type <a href="#service-worker-container-message-event">message</a>, which does not bubble and is not cancelable.</li>
            <li>Let the {{ServiceWorkerMessageEvent/data}} attribute of <var>e</var> be initialized to <var>clonedMessage</var>.</li>
            <li>Let the {{ServiceWorkerMessageEvent/origin}} attribute of <var>e</var> be initialized to the <a lt="unicode serialisation of an origin">Unicode serialisation</a> of <var>sourceSettings</var>'s <a for="resource">origin</a>.</li>
            <li>Let the {{ServiceWorkerMessageEvent/source}} attribute of <var>e</var> be initialized to a {{ServiceWorker}} object, which represents the <a href="#dfn-service-worker-global-scope-service-worker">service worker</a> associated with <var>sourceSettings</var>'s <a lt="the environment settings object's global object">global object</a>.</li>
            <li>Let the {{ServiceWorkerMessageEvent/ports}} attribute of <var>e</var> be initialized to <var>newPorts</var>.</li>
            <li><a>Dispatch</a> <var>e</var> at <var>destination</var>.</li>
          </ol>
        </li>
      </ol>
    </section>

    <section>
      <h4 id="client-visibilitystate">{{WindowClient/visibilityState}}</h4>

      <p>The <dfn attribute for="WindowClient" id="client-visibilitystate-attribute"><code>visibilityState</code></dfn> attribute <em class="rfc2119" title="MUST">must</em> return the <a>context object</a>'s <a href="#dfn-service-worker-client-visibilitystate">visibility state</a>.</p>
    </section>

    <section>
      <h4 id="client-focused">{{WindowClient/focused}}</h4>

      <p>The <dfn attribute for="WindowClient" id="client-focused-attribute"><code>focused</code></dfn> attribute <em class="rfc2119" title="MUST">must</em> return the <a>context object</a>'s <a href="#dfn-service-worker-client-focusstate">focus state</a>.</p>
    </section>

    <section algorithm="client-focus">
      <h4 id="client-focus">{{WindowClient/focus()}}</h4>

      <p>The <dfn method for="WindowClient" id="client-focus-method"><code>focus()</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>If this algorithm is not <a>triggered by user activation</a>, return a <a>promise</a> rejected with an "{{InvalidAccessError}}" exception.</li>
        <li>Let <var>promise</var> be a new <a>promise</a>.</li>
        <li>Run these substeps <a>in parallel</a>:
          <ol>
            <li>Let <var>browsingContext</var> be the <a>context object</a>'s associated <a href="#dfn-service-worker-client-client">service worker client</a>'s <a>global object</a>'s <a>browsing context</a>.</li>
            <li>Let <var>visibilityState</var> be null.</li>
            <li>Let <var>focusState</var> be null.</li>
            <li><a>Queue a task</a> <var>task</var> to run the following substeps on the <a>context object</a>'s associated <a href="#dfn-service-worker-client-client">service worker client</a>'s <a>responsible event loop</a> using the <a>user interaction task source</a>:
              <ol>
                <li>Run the <a>focusing steps</a> with <var>browsingContext</var>.</li>
                <li>Set <var>visibilityState</var> to <var>browsingContext</var>'s <a>active document</a>'s {{Document/visibilityState}} attribute value.</li>
                <li>Set <var>focusState</var> to the result of running the <a>has focus steps</a> with <var>browsingContext</var>'s <a>active document</a> as the argument.</li>
              </ol>
            </li>
            <li>Wait for <var>task</var> to have executed.</li>
            <li>Let <var>windowClient</var> be the result of running <a href="#create-windowclient-algorithm">Create Window Client</a> algorithm with the <a>context object</a>'s associated <a href="#dfn-service-worker-client-client">service worker client</a>, <var>visibilityState</var> and <var>focusState</var> as the arguments.</li>
            <li>If <var>windowClient</var>'s <a href="#dfn-service-worker-client-focusstate">focus state</a> is true, resolve <var>promise</var> with <var>windowClient</var>.</li>
            <li>Else, reject <var>promise</var> with a <code>TypeError</code>.</li>
          </ol>
        </li>
        <li>Return <var>promise</var>.</li>
      </ol>
    </section>

    <section algorithm="client-navigate">
      <h4 id="client-navigate">{{WindowClient/navigate(url)}}</h4>

      <p>The <dfn method for="WindowClient" id="client-navigate-method"><code>navigate()</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>Let <var>url</var> be the result of <a for="url">parsing</a> <var>url</var> with the <a>context object</a>'s <a>relevant settings object</a>'s <a>API base URL</a>.</li>
        <li>If <var>url</var> is failure, return a <a>promise</a> rejected with a <code>TypeError</code>.</li>
        <li>If <var>url</var> is <code><a>about:blank</a></code>, return a <a>promise</a> rejected with a <code>TypeError</code>.</li>
        <li>If the <a>context object</a>'s associated <a href="#dfn-service-worker-client-client">service worker client</a>'s <a href="#dfn-service-worker-client-active-worker">active worker</a> is not the <a>context object</a>'s <a>relevant global object</a>'s <a href="#dfn-service-worker-global-scope-service-worker">service worker</a>, return a <a>promise</a> rejected with a <code>TypeError</code>.</li>
        <li>Let <var>promise</var> be a new <a>promise</a>.</li>
        <li>Run these substeps <a>in parallel</a>:
          <ol>
            <li>Let <var>browsingContext</var> be the <a>context object</a>'s associated <a href="#dfn-service-worker-client-client">service worker client</a>'s <a>global object</a>'s <a>browsing context</a>.</li>
            <li>If <var>browsingContext</var> has <a lt="discard a document">discarded</a> its {{Document}}, reject <var>promise</var> with a <code>TypeError</code> and abort these steps.</li>
            <li>Let <var>navigateFailed</var> to false.</li>
            <li>Let <var>visibilityState</var> be null.</li>
            <li>Let <var>focusState</var> be null.</li>
            <li><a>Queue a task</a> <var>task</var> to run the following substeps on the <a>context object</a>'s associated <a href="#dfn-service-worker-client-client">service worker client</a>'s <a>responsible event loop</a> using the <a>user interaction task source</a>:
              <ol>
                <li><em>HandleNavigate</em>: <a>Navigate</a> <var>browsingContext</var> to <var>url</var> with <a>replacement enabled</a> and <a lt="exceptions enabled flag">exceptions enabled</a>. The <a>source browsing context</a> must be <var>browsingContext</var>.</li>
                <li>If the algorithm steps invoked in the step labeled <em>HandleNavigate</em> <a>throws</a> an exception, set <var>navigateFailed</var> to true.</li>
                <li>Set <var>visibilityState</var> to <var>browsingContext</var>'s <a>active document</a>'s {{Document/visibilityState}} attribute value.</li>
                <li>Set <var>focusState</var> to the result of running the <a>has focus steps</a> with <var>browsingContext</var>'s <a>active document</a> as the argument.</li>
              </ol>
            </li>
            <li>Wait for <var>task</var> to have executed (including its asynchronous steps).</li>
            <li>If <var>navigateFailed</var> is true, reject <var>promise</var> with a <code>TypeError</code> and abort these steps.</li>
            <li>If <var>browsingContext</var>'s {{Window}} object's <a>environment settings object</a>'s <a>creation url</a>'s <a for="resource">origin</a> is not the <a lt="same origin">same</a> as the <a href="#dfn-service-worker-global-scope-service-worker">service worker</a>'s <a for="resource">origin</a>, then:
              <ol>
                <li>Resolve <var>promise</var> with null.</li>
                <li>Abort these steps.</li>
              </ol>
            </li>
            <li>Let <var>windowClient</var> be the result of running <a href="#create-windowclient-algorithm">Create Window Client</a> algorithm with <var>browsingContext</var>'s {{Window}} object's <a>environment settings object</a>, <var>visibilityState</var> and <var>focusState</var> as the arguments.</li>
            <li>Resolve <var>promise</var> with <var>windowClient</var>.</li>
          </ol>
        </li>
        <li>Return <var>promise</var>.</li>
      </ol>
    </section>
  </section>

  <section dfn-for="Clients">
    <h3 id="clients">{{Clients}}</h3>

    <pre class="idl">
      [Exposed=ServiceWorker]
      interface Clients {
        // The objects returned will be new instances every time
        [NewObject] Promise&lt;any&gt; get(DOMString id);
        [NewObject] Promise&lt;sequence&lt;Client&gt;&gt; matchAll(optional ClientQueryOptions options);
        [NewObject] Promise&lt;WindowClient?&gt; openWindow(USVString url);
        [NewObject] Promise&lt;void&gt; claim();
      };
    </pre>
    <pre class="idl" id="serviceworker-client-query-options-dictionary">
      dictionary ClientQueryOptions {
        boolean includeUncontrolled = false;
        ClientType type = "window";
      };
    </pre>
    <pre class="idl" id="client-type-enum">
      enum ClientType {
        "window",
        "worker",
        "sharedworker",
        "all"
      };
    </pre>

    <p>The user agent <em class="rfc2119" title="MUST">must</em> create a <code><dfn interface id="clients-interface">Clients</a></code> object when a <code><a href="#service-worker-global-scope-interface">ServiceWorkerGlobalScope</a></code> object is created and associate it with that object.</p>

    <section algorithm="clients-get">
      <h4 id="clients-get">{{Clients/get(id)}}</h4>

      <p>The <dfn method id="clients-get-method"><code>get(<var>id</var>)</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>Let <var>promise</var> be a new <a>promise</a>.</li>
        <li>Run these substeps <a>in parallel</a>:
          <ol>
            <li>For each <a href="#dfn-service-worker-client">service worker client</a> <var>client</var> whose <a for="resource">origin</a> is the <a lt="same origin">same</a> as the associated <a href="#dfn-service-worker-global-scope-service-worker">service worker</a>'s <a for="resource">origin</a>:
              <ol>
                <li>If <var>client</var>'s <a href="#dfn-service-worker-client-id">id</a> is <var>id</var>, then:
                  <ol>
                    <li>If <var>client</var> is not a <a>secure context</a>, reject <var>promise</var> with a "{{SecurityError}}" exception and abort these steps.</li>
                    <li>If <var>client</var> is a <a href="#dfn-window-client">window client</a>, then:
                      <ol>
                        <li>Let <var>browsingContext</var> be <var>client</var>'s <a>global object</a>'s <a>browsing context</a>.</li>
                        <li>Let <var>visibilityState</var> be null.</li>
                        <li>Let <var>focusState</var> be null.</li>
                        <li><a>Queue a task</a> <var>task</var> to run the following substeps:
                          <ol>
                            <li>Set <var>visibilityState</var> to <var>browsingContext</var>'s <a>active document</a>'s {{Document/visibilityState}} attribute value.</li>
                            <li>Set <var>focusState</var> to the result of running the <a>has focus steps</a> with <var>browsingContext</var>'s <a>active document</a> as the argument.</li>
                          </ol>
                        </li>
                        <li>Wait for <var>task</var> to have executed.</li>
                        <li>Let <var>windowClient</var> be the result of running <a href="#create-windowclient-algorithm">Create Window Client</a> algorithm with <var>client</var>, <var>visibilityState</var> and <var>focusState</var> as the arguments.</li>
                        <li>Resolve <var>promise</var> with <var>windowClient</var> and abort these steps.</li>
                      </ol>
                    </li>
                    <li>Else:
                      <ol>
                        <li>Let <var>clientObject</var> be the result of running <a href="#create-client-algorithm">Create Client</a> algorithm with <var>client</var> as the argument.</li>
                        <li>Resolve <var>promise</var> with <var>clientObject</var> and abort these steps.</li>
                      </ol>
                    </li>
                  </ol>
                </li>
              </ol>
            </li>
            <li>Resolve <var>promise</var> with undefined.</li>
          </ol>
        </li>
        <li>Return <var>promise</var>.</li>
      </ol>
    </section>

    <section algorithm="clients-getall">
      <h4 id="clients-getall">{{Clients/matchAll(options)}}</h4>

      <p>The <dfn method id="clients-matchall-method"><code>matchAll(<var>options</var>)</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>Let <var>promise</var> be a new <a>promise</a>.</li>
        <li>Run these substeps <a>in parallel</a>:
          <ol>
            <li>Let <var>targetClients</var> be an empty array.</li>
            <li>For each <a href="#dfn-service-worker-client">service worker client</a> <var>client</var> whose <a for="resource">origin</a> is the <a lt="same origin">same</a> as the associated <a href="#dfn-service-worker-global-scope-service-worker">service worker</a>'s <a for="resource">origin</a>:
              <ol>
                <li>If <var>client</var> is not a <a>secure context</a>, continue to the next iteration of the loop.</li>
                <li>If <var>options</var>.{{ClientQueryOptions/includeUncontrolled}} is false, then:
                  <ol>
                    <li>If <var>client</var>'s <a href="#dfn-service-worker-client-active-worker">active worker</a> is the associated <a href="#dfn-service-worker-global-scope-service-worker">service worker</a>, add <var>client</var> to <var>targetClients</var>.</li>
                  </ol>
                </li>
                <li>Else:
                  <ol>
                    <li>Add <var>client</var> to <var>targetClients</var>.</li>
                  </ol>
                </li>
              </ol>
            </li>
            <li>Let <var>matchedClients</var> be an empty array.</li>
            <li>For each <a href="#dfn-service-worker-client">service worker client</a> <var>client</var> in <var>targetClients</var>, in the most recently <a lt="focusing steps">focused</a> order for <a href="#dfn-window-client">window clients</a>:
              <ol>
                <li>If <var>options</var>.{{ClientQueryOptions/type}} is "<code>window</code>", and <var>client</var> is a <a href="#dfn-window-client">window client</a>, then:
                  <ol>
                    <li>Let <var>browsingContext</var> be <var>client</var>'s <a>global object</a>'s <a>browsing context</a>.</li>
                    <li>Let <var>isClientEnumerable</var> be false.</li>
                    <li>Let <var>visibilityState</var> be the empty string.</li>
                    <li>Let <var>focusState</var> be false.</li>
                    <li><a>Queue a task</a> <var>task</var> to run the following substep on <var>client</var>'s <a>responsible event loop</a> using the <a>user interaction task source</a>:
                      <ol>
                        <li>If <var>browsingContext</var> has not been <a lt="a browsing context is discarded">discarded</a> and <var>client</var>'s <a>responsible document</a> is <var>browsingContext</var>'s <a>active document</a>, then:
                          <ol>
                            <li>Set <var>visibilityState</var> to <var>browsingContext</var>'s <a>active document</a>'s {{Document/visibilityState}} attribute value.</li>
                            <li>Set <var>focusState</var> to the result of running the <a>has focus steps</a> with <var>browsingContext</var>'s <a>active document</a> as the argument.</li>
                            <li>Set <var>isClientEnumerable</var> to true.</li>
                          </ol>
                        </li>
                      </ol>
                    </li>
                    <li>Wait for <var>task</var> to have executed.
                      <p class="note">Wait is a blocking wait, but implementers may run the iterations in parallel as long as the state is not broken.</p>
                    </li>
                    <li>If <var>isClientEnumerable</var> is true, then:
                      <ol>
                        <li>Let <var>windowClient</var> be the result of running <a href="#create-windowclient-algorithm">Create Window Client</a> algorithm with <var>client</var>, <var>visibilityState</var> and <var>focusState</var> as the arguments.</li>
                        <li>Add <var>windowClient</var> to <var>matchedClients</var>.</li>
                      </ol>
                    </li>
                  </ol>
                </li>
                <li>Else if <var>options</var>.{{ClientQueryOptions/type}} is "<code>worker</code>" and <var>client</var> is a <a href="#dfn-dedicatedworker-client">dedicated worker client</a>, or <var>options</var>.{{ClientQueryOptions/type}} is "<code>sharedworker</code>" and <var>client</var> is a <a href="#dfn-sharedworker-client">shared worker client</a>, then:
                  <ol>
                    <li>Let <var>clientObject</var> be the result of running <a href="#create-client-algorithm">Create Client</a> algorithm with <var>client</var> as the argument.</li>
                    <li>Add <var>clientObject</var> to <var>matchedClients</var>.</li>
                  </ol>
                </li>
                <li>Else if <var>options</var>.{{ClientQueryOptions/type}} is "<code>all</code>", then:
                  <ol>
                    <li>If <var>client</var> is a <a href="#dfn-window-client">window client</a>, then:
                      <ol>
                        <li>Let <var>browsingContext</var> be <var>client</var>'s <a>global object</a>'s <a>browsing context</a>.</li>
                        <li>Let <var>isClientEnumerable</var> be false.</li>
                        <li>Let <var>visibilityState</var> be the empty string.</li>
                        <li>Let <var>focusState</var> be false.</li>
                        <li><a>Queue a task</a> <var>task</var> to run the following substep on <var>client</var>'s <a>responsible event loop</a> using the <a>user interaction task source</a>:
                          <ol>
                            <li>If <var>browsingContext</var> has not been <a lt="a browsing context is discarded">discarded</a> and <var>client</var>'s <a>responsible document</a> is <var>browsingContext</var>'s <a>active document</a>, then:
                              <ol>
                                <li>Set <var>visibilityState</var> to <var>browsingContext</var>'s <a>active document</a>'s {{Document/visibilityState}} attribute value.</li>
                                <li>Set <var>focusState</var> to the result of running the <a>has focus steps</a> with <var>browsingContext</var>'s <a>active document</a> as the argument.</li>
                                <li>Set <var>isClientEnumerable</var> to true.</li>
                              </ol>
                            </li>
                          </ol>
                        </li>
                        <li>Wait for <var>task</var> to have executed.
                          <p class="note">Wait is a blocking wait, but implementers may run the iterations in parallel as long as the state is not broken.</p>
                        </li>
                        <li>If <var>isClientEnumerable</var> is true, then:
                          <ol>
                            <li>Let <var>windowClient</var> be the result of running <a href="#create-windowclient-algorithm">Create Window Client</a> algorithm with <var>client</var>, <var>visibilityState</var> and <var>focusState</var> as the arguments.</li>
                            <li>Add <var>windowClient</var> to <var>matchedClients</var>.</li>
                          </ol>
                        </li>
                      </ol>
                    </li>
                    <li>Else:
                      <ol>
                        <li>Let <var>clientObject</var> be the result of running <a href="#create-client-algorithm">Create Client</a> algorithm with <var>client</var> as the argument.</li>
                        <li>Add <var>clientObject</var> to <var>matchedClients</var>.</li>
                      </ol>
                    </li>
                  </ol>
              </ol>
            </li>
            <li>Resolve <var>promise</var> with <var>matchedClients</var>.</li>
          </ol>
        </li>
        <li>Return <var>promise</var>.</li>
      </ol>
    </section>

    <section algorithm="clients-openwindow">
      <h4 id="clients-openwindow">{{Clients/openWindow(url)}}</h4>

      <p>The <dfn method id="clients-openwindow-method"><code>openWindow(<var>url</var>)</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>Let <var>url</var> be the result of <a for="url">parsing</a> <var>url</var> with the <a>context object</a>'s <a>relevant settings object</a>'s <a>API base URL</a>.</li>
        <li>If <var>url</var> is failure, return a <a>promise</a> rejected with a <code>TypeError</code>.</li>
        <li>If <var>url</var> is <code><a>about:blank</a></code>, return a <a>promise</a> rejected with a <code>TypeError</code>.</li>
        <li>If this algorithm is not <a>triggered by user activation</a>, return a <a>promise</a> rejected with an "{{InvalidAccessError}}" exception.</li>
        <li>Let <var>promise</var> be a new <a>promise</a>.</li>
        <li>Run these substeps <a>in parallel</a>:
          <ol>
            <li>Let <var>newContext</var> be a new <a>top-level browsing context</a>.</li>
            <li>Let <var>openWindowFailed</var> to false.</li>
            <li>Let <var>visibilityState</var> be null.</li>
            <li>Let <var>focusState</var> be null.</li>
            <li><a>Queue a task</a> <var>task</var> to run the following substeps on <var>newContext</var>'s {{Window}} object's <a>environment settings object</a>'s <a>responsible event loop</a> using the <a>user interaction task source</a>:
              <ol>
                <li><em>HandleNavigate</em>: <a>Navigate</a> <var>newContext</var> to <var>url</var>, with <a lt="exceptions enabled flag">exceptions enabled</a> and <a>replacement enabled</a>.</li>
                <li>If the algorithm steps invoked in the step labeled <em>HandleNavigate</em> <a>throws</a> an exception, set <var>openWindowFailed</var> to true.</li>
                <li>Set <var>visibilityState</var> to <var>newContext</var>'s <a>active document</a>'s {{Document/visibilityState}} attribute value.</li>
                <li>Set <var>focusState</var> to the result of running the <a>has focus steps</a> with <var>newContext</var>'s <a>active document</a> as the argument.</li>
              </ol>
            </li>
            <li>Wait for <var>task</var> to have executed (including its asynchronous steps).</li>
            <li>If <var>openWindowFailed</var> is true, reject <var>promise</var> with a <code>TypeError</code> and abort these steps.</li>
            <li>If <var>newContext</var>'s {{Window}} object's <a>environment settings object</a>'s <a>creation url</a>'s <a for="resource">origin</a> is not the <a lt="same origin">same</a> as the <a href="#dfn-service-worker-global-scope-service-worker">service worker</a>'s <a for="resource">origin</a>, then:
              <ol>
                <li>Resolve <var>promise</var> with null.</li>
                <li>Abort these steps.</li>
              </ol>
            </li>
            <li>Let <var>client</var> be the result of running <a href="#create-windowclient-algorithm">Create Window Client</a> algorithm with <var>newContext</var>'s {{Window}} object's <a>environment settings object</a>, <var>visibilityState</var> and <var>focusState</var> as the arguments.</li>
            <li>Resolve <var>promise</var> with <var>client</var>.</li>
          </ol>
        </li>
        <li>Return <var>promise</var>.</li>
      </ol>
    </section>

    <section algorithm="clients-claim">
      <h4 id="clients-claim">{{Clients/claim()}}</h4>

      <p>The <dfn method id="clients-claim-method"><code>claim()</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>If the <a href="#dfn-service-worker-global-scope-service-worker">service worker</a> is not an <a href="#dfn-active-worker">active worker</a>, return a <a>promise</a> rejected with an "{{InvalidStateError}}" exception.</li>
        <li>Let <var>promise</var> be a new <a>promise</a>.</li>
        <li>Run the following substeps <a>in parallel</a>:
          <ol>
            <li>For each <a href="#dfn-service-worker-client">service worker client</a> <var>client</var> whose <a for="resource">origin</a> is the <a lt="same origin">same</a> as the <a href="#dfn-service-worker-global-scope-service-worker">service worker</a>'s <a for="resource">origin</a>:
              <ol>
                <li>If <var>client</var> is not a <a>secure context</a>, continue to the next iteration of the loop.</li>
                <li>Let <var>registration</var> be the result of running <a href="#scope-match-algorithm">Match Service Worker Registration</a> algorithm passing <var>client</var>'s <a>creation url</a> as the argument.</li>
                <li>If <var>registration</var> is not the <a href="#dfn-service-worker-global-scope-service-worker">service worker</a>'s <a href="#dfn-containing-service-worker-registration">containing service worker registration</a>, continue to the next iteration of the loop.</li>
                <li>If <var>client</var>'s <a href="#dfn-active-worker">active worker</a> is not the <a href="#dfn-service-worker-global-scope-service-worker">service worker</a>, then:
                  <ol>
                    <li>Invoke <a href="#on-client-unload-algorithm">Handle Service Worker Client Unload</a> with <var>client</var> as the argument.</li>
                    <li>Set <var>client</var>'s <a href="#dfn-active-worker">active worker</a> to <a href="#dfn-service-worker-global-scope-service-worker">service worker</a>.</li>
                    <li>Invoke <a href="#notify-controller-change-algorithm">Notify Controller Change</a> algorithm with <var>client</var> as the argument.</li>
                  </ol>
                </li>
              </ol>
            </li>
            <li>Resolve <var>promise</var> with undefined.</li>
          </ol>
        </li>
        <li>Return <var>promise</var>.</li>
      </ol>
    </section>
  </section>

  <section>
    <h3 id="extendable-event">{{ExtendableEvent}}</h3>

    <pre class="idl">
      [Constructor(DOMString type, optional ExtendableEventInit eventInitDict), Exposed=ServiceWorker]
      interface ExtendableEvent : Event {
        void waitUntil(Promise&lt;any&gt; f);
      };
    </pre>
    <pre class="idl" id="extendable-event-init-dictionary">
      dictionary ExtendableEventInit : EventInit {
        // Defined for the forward compatibility across the derived events
      };
    </pre>

    <p>An <code><dfn interface id="extendable-event-interface" title="ExtendableEvent">ExtendableEvent</dfn></code> object has an associated <dfn id="dfn-extend-lifetime-promises">extend lifetime promises</dfn> (an array of <a>promises</a>). It is initially an empty array.</p>

    <p>An {{ExtendableEvent}} object has an associated <dfn id="extensions-allowed-flag">extensions allowed flag</dfn>. It is initially set.</p>

    <p><a href="#dfn-service-worker">Service workers</a> have two <a href="#dfn-lifecycle-events">lifecycle events</a>, <code><a href="#service-worker-global-scope-install-event">install</a></code> and <code><a href="#service-worker-global-scope-activate-event">activate</a></code>. <a href="#dfn-service-worker">Service workers</a> use the {{ExtendableEvent}} interface for <code><a href="#service-worker-global-scope-activate-event">activate</a></code> event and <code><a href="#service-worker-global-scope-install-event">install</a></code> event.</p>

    <p><a href="#extensibility">Service worker extensions</a> that <a href="#extension-to-service-worker-global-scope">define event handlers</a> <em class="rfc2119" title="MAY">may</em> also use or extend the {{ExtendableEvent}} interface.</p>

    <p>When <a>dispatching</a> an event <var>e</var> that uses the {{ExtendableEvent}} interface, the user agent <em class="rfc2119" title="MUST">must</em> run these steps:</p>

    <ol>
      <li>If <var>e</var>'s <a>extend lifetime promises</a> is empty, unset <var>e</var>'s <a>extensions allowed flag</a> and abort these steps.</li>
      <li>Let <var>extendLifetimePromises</var> be an empty array.</li>
      <li>Run the following substeps <a>in parallel</a>:
        <ol>
          <li><em>SetupPromiseArray</em>: Set <var>extendLifetimePromises</var> to a copy of <var>e</var>'s <a>extend lifetime promises</a>.</li>
          <li>Wait until all the <a>promises</a> in <var>extendLifetimePromises</var> settle.</li>
          <li>If the length of <var>extendLifetimePromises</var> does not equal the length of <var>e</var>'s <a>extend lifetime promises</a>, jump to the step labeled <em>SetupPromiseArray</em>.</li>
          <li>Unset <var>e</var>'s <a>extensions allowed flag</a>.</li>
        </ol>
      </li>
    </ol>

    <p>The user agent <em class="rfc2119" title="SHOULD NOT">should not</em> <a href="#terminate-service-worker-algorithm">terminate</a> the <a for="/">service worker</a> associated with <var>e</var>'s <a>relevant settings object</a>'s <a>global object</a> until <var>e</var>'s <a>extensions allowed flag</a> is unset. However, the user agent <em class="rfc2119" title="MAY">may</em> impose a time limit to this lifetime extension.</p>

    <section algorithm="wait-until-method">
      <h4 id="wait-until-method">{{ExtendableEvent/waitUntil(f)|event.waitUntil(f)}}</h4>

      <p>{{ExtendableEvent/waitUntil(f)}} method extends the lifetime of the event.</p>

      <p><dfn method for="ExtendableEvent" id="extendable-event-waituntil-method"><code>waitUntil(<var>f</var>)</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>If the <a>extensions allowed flag</a> is unset, then:
          <ol>
            <li><a>Throw</a> an "{{InvalidStateError}}" exception.</li>
            <li>Abort these steps.</li>
          </ol>
        </li>
        <li>Add <var>f</var> to the <a href="#dfn-extend-lifetime-promises">extend lifetime promises</a>.</li>
      </ol>
    </section>

    <p><a href="#dfn-service-worker">Service workers</a> and <a href="#extensibility">extensions</a> that <a href="#extension-to-service-worker-global-scope">define event handlers</a> <em class="rfc2119" title="MAY">may</em> define their own behaviors, allowing the <a href="#dfn-extend-lifetime-promises">extend lifetime promises</a> to suggest operation length, and the rejected state of any of the <a>promise</a> in <a href="#dfn-extend-lifetime-promises">extend lifetime promises</a> to suggest operation failure.</p>

    <p><a href="#dfn-service-worker">Service workers</a> define the following behaviors for <code><a href="#service-worker-global-scope-install-event">install</a></code> event and <code><a href="#service-worker-global-scope-activate-event">activate</a></code> event, respectively:</p>

    <ul>
      <li>Adding a <a>promise</a> <var>f</var> to the event's <a>extend lifetime promises</a> delays treating the <a href="#dfn-installing-worker">installing worker</a> as <em><a href="#dfn-state">installed</a></em> (i.e. a <a href="#dfn-waiting-worker">waiting worker</a>) until all the <a>promises</a> in the <a>extend lifetime promises</a> resolve successfully. (See step 11.3.1 of <a href="#installation-algorithm">Install</a> algorithm.) If <var>f</var> rejects, the installation fails. This is primarily used to ensure that a <a href="#dfn-service-worker">service worker</a> is not considered <em><a href="#dfn-state">installed</a></em> (i.e. a <a href="#dfn-waiting-worker">waiting worker</a>) until all of the core caches it depends on are populated.</li>
      <li>Adding a <a>promise</a> to the event's <a>extend lifetime promises</a> delays treating the <a href="#dfn-active-worker">active worker</a> as <em><a href="#dfn-state">activated</a></em> until all the <a>promises</a> in the <a>extend lifetime promises</a> settle. (See step 12.3 of <a href="#activation-algorithm">Activate</a> algorithm.) This is primarily used to ensure that any <a href="#dfn-functional-events">functional events</a> are not dispatched to the {{ServiceWorkerGlobalScope}} object that represents the <a href="#dfn-service-worker">service worker</a> until it upgrades database schemas and deletes the outdated cache entries.</li>
    </ul>
  </section>

  <section dfn-for="InstallEvent">
    <h3 id="install-event-section">{{InstallEvent}}</h3>

    <pre class="idl">
      [Constructor(DOMString type, optional ExtendableEventInit eventInitDict), Exposed=ServiceWorker]
      interface InstallEvent : ExtendableEvent {
        void registerForeignFetch(ForeignFetchOptions options);
      };

      dictionary ForeignFetchOptions {
        required sequence&lt;USVString&gt; scopes;
        required sequence&lt;USVString&gt; origins;
      };
    </pre>

    <section>
      <h4 id="register-foreign-fetch-method">{{InstallEvent/registerForeignFetch(options)|event.registerForeignFetch(options)}}</h4>

      <p>{{InstallEvent/registerForeignFetch(options)}} registers this service worker to handle foreign fetches from certain origins for certain sub scopes.</p>

      <p><dfn method><code>registerForeignFetch(<var>options</var>)</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>
      <ol>
        <li>If the <a>dispatch flag</a> is unset, then:
          <ol>
            <li><a href="http://heycam.github.io/webidl/#dfn-throw">Throw</a> an "<code><a href="http://heycam.github.io/webidl/#invalidstateerror">InvalidStateError</a></code>" exception.</li>
            <li>Abort these steps.</li>
          </ol>
        </li>
        <li>If <var>options</var>.{{ForeignFetchOptions/origins}} is empty <a>throw</a> a <code>TypeError</code> and abort these steps.</li>
        <li>Let <var>originURLs</var> be an empty list of <a for="url">URLs</a>.</li>
        <li>If the value of <var>options</var>.{{ForeignFetchOptions/origins}} is not a single string equal to a single U+002A ASTERISK character (*):
          <ol>
            <li>For each <var>origin</var> in <var>options</var>.<var>origins</var>:
              <ol>
                <li>If the value of <var>origin</var> is not an <a>absolute URL</a>, <a>throw</a> a <code>TypeError</code> and abort these steps.</li>
                <li>Add the result of <a for="url">parsing</a> <var>origin</var> to <var>originURLs</var>.</li>
              </ol>
            </li>
          </ol>
        </li>
        <li>If <var>options</var>.{{ForeignFetchOptions/scopes}} is empty <a>throw</a> a <code>TypeError</code> and abort these steps.</li>
        <li>Let <var>scopeString</var> be the <a>context object</a>'s <a>relevant global object</a>'s <a for="ServiceWorkerGlobalScope">service worker</a>'s <a>containing service worker registration</a>'s <a for="service worker registration">scope url</a>, <a for="url">serialized</a>.</li>
        <li>Let <var>subScopeURLs</var> be an empty list of <a for="url">URLs</a>.</li>
        <li>For each <var>subScope</var> in <var>options</var>.{{ForeignFetchOptions/scopes}}:
          <ol>
            <li>Let <var>subScopeURL</var> be the result of <a for="url">parsing</a> <var>subScope</var> with <a>context object</a>'s <a>relevant settings object</a>'s <a>API base URL</a>.</li>
            <li>If <var>subScopeURL</var> is failure, <a>throw</a> a <code>TypeError</code> and abort these steps.</li>
            <li>Let <var>subScopeString</var> be the <a for="url">serialized</a> <var>subScopeURL</var>.</li>
            <li>If <var>subScopeString</var> does not start with <var>scopeString</var>, <a>throw</a> a <code>TypeError</code> and abort these steps.</li>
            <li>Add <var>subScopeURL</var> to <var>subScopeURLs</var>.</li>
          </ol>
        </li>
        <li>Set this <a href="#dfn-service-worker">service worker</a>'s <a>list of foreign fetch scopes</a> to <var>subScopeURLs</var>.</li>
        <li>Set this <a href="#dfn-service-worker">service worker</a>'s <a>list of foreign fetch origins</a> to <var>originURLs</var>.</li>
      </ol>
    </section>
  </section>

  <section dfn-for="FetchEvent">
    <h3 id="fetch-event-section">{{FetchEvent}}</h3>

    <pre class="idl">
      [Constructor(DOMString type, FetchEventInit eventInitDict), Exposed=ServiceWorker]
      interface FetchEvent : ExtendableEvent {
        [SameObject] readonly attribute Request request;
        readonly attribute DOMString? clientId;
        readonly attribute boolean isReload;

        void respondWith(Promise&lt;Response&gt; r);
      };
    </pre>
    <pre class="idl" id="fetch-event-init-dictionary">
      dictionary FetchEventInit : ExtendableEventInit {
        required Request request;
        DOMString? clientId = null;
        boolean isReload = false;
      };
    </pre>

    <p><a href="#dfn-service-worker">Service workers</a> have an essential <a href="#dfn-functional-events">functional event</a> <code><a href="#service-worker-global-scope-fetch-event">fetch</a></code>. For <code><a href="#service-worker-global-scope-fetch-event">fetch</a></code> event, <a href="#dfn-service-worker">service workers</a> use the <code><dfn interface id="fetch-event-interface">FetchEvent</dfn></code> interface which extends the {{ExtendableEvent}} interface.</p>

    <p>Each event using {{FetchEvent}} interface has an associated <dfn>potential response</dfn> (a <a for="fetch">response</a>), initially set to null, and the following associated flags that are initially unset:
      <ul>
        <li><dfn id="wait-to-respond-flag">wait to respond flag</dfn></li>
        <li><dfn id="respond-with-entered-flag">respond-with entered flag</dfn></li>
        <li><dfn id="respond-with-error-flag">respond-with error flag</dfn></li>
      </ul>
    </p>

    <section>
      <h4 id="fetch-event-request">{{FetchEvent/request|event.request}}</h4>

      <p><dfn attribute id="fetch-event-request-attribute"><code>request</code></dfn> attribute <em class="rfc2119" title="MUST">must</em> return the value it was initialized to.</p>
    </section>

    <section>
      <h4 id="fetch-event-clientid">{{FetchEvent/clientId|event.clientId}}</h4>

      <p><dfn attribute id="fetch-event-clientid-attribute"><code>clientId</code></dfn> attribute <em class="rfc2119" title="MUST">must</em> return the value it was initialized to. When an <a>event</a> is created the attribute <em class="rfc2119" title="MUST">must</em> be initialized to null.</p>
    </section>

    <section>
      <h4 id="fetch-event-isreload">{{FetchEvent/isReload|event.isReload}}</h4>

      <p><dfn attribute id="fetch-event-isreload-attribute"><code>isReload</code></dfn> attribute <em class="rfc2119" title="MUST">must</em> return the value it was initialized to. When an <a>event</a> is created the attribute <em class="rfc2119" title="MUST">must</em> be initialized to false.</p>

      <p class="note">Pressing the refresh button should be considered a reload while clicking a link and pressing the back button should not. The behavior of the <var>Ctrl+l enter</var> is left to the implementations of the user agents.</p>
    </section>

    <section algorithm="fetch-event-respondwith">
      <h4 id="fetch-event-respondwith">{{FetchEvent/respondWith(r)|event.respondWith(r)}}</h4>

      <p class="note">Developers can set the argument <var>r</var> with either a <a>promise</a> that resolves with a {{Response}} object or a {{Response}} object (which is automatically cast to a promise). Otherwise, a <a>network error</a> is returned to <a>Fetch</a>. Renderer-side security checks about tainting for cross-origin content are tied to the types of <a>filtered responses</a> defined in <a>Fetch</a>.</p>

      <p><dfn method id="fetch-event-respondwith-method"><code>respondWith(<var>r</var>)</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol link-for-hint="FetchEvent">
        <li>If the <a>dispatch flag</a> is unset, then:
          <ol>
            <li><a>Throw</a> an "{{InvalidStateError}}" exception.</li>
            <li>Abort these steps.</li>
          </ol>
        </li>
        <li>If the <a href="#respond-with-entered-flag">respond-with entered flag</a> is set, then:
          <ol>
            <li><a>Throw</a> an "{{InvalidStateError}}" exception.</li>
            <li>Abort these steps.</li>
          </ol>
        </li>
        <li>Add <var>r</var> to the <a>extend lifetime promises</a>.
          <p class="note">{{FetchEvent/respondWith(r)|event.respondWith(r)}} extends the lifetime of the event by default as if {{ExtendableEvent/waitUntil(f)|event.waitUntil(r)}} is called.</p>
        </li>
        <li>Set the <a>stop propagation flag</a> and <a>stop immediate propagation flag</a>.</li>
        <li>Set the <a href="#respond-with-entered-flag">respond-with entered flag</a>.</li>
        <li>Set the <a href="#wait-to-respond-flag">wait to respond flag</a>.</li>
        <li>Let <var>targetRealm</var> be the <a>relevant Realm</a> of the <a>context object</a>.
        <li>Run the following substeps <a>in parallel</a>:
          <ol>
            <li>Wait until <var>r</var> settles.</li>
            <li>If <var>r</var> rejected, then:
              <ol>
                <li>Set the <a href="#respond-with-error-flag">respond-with error flag</a>.</li>
              </ol>
            </li>
            <li>If <var>r</var> resolved with <var>response</var>, then:
              <ol>
                <li>If <var>response</var> is a {{Response}} object, then:
                  <ol>
                    <li>If <var>response</var> is <a>disturbed</a> or <a>locked</a>, then:
                      <ol>
                        <li>Set the <a href="#respond-with-error-flag">respond-with error flag</a>.</li>
                      </ol>
                    </li>
                    <li>Else:
                      <ol>
                        <li>Let <var>bytes</var> be an empty byte sequence.
                        <li>Let <var>end-of-body</var> be false.
                        <li>Let <var>done</var> be false.
                        <li>Let <var>potentialResponse</var> be a copy of <var>response</var>'s associated <a href="https://fetch.spec.whatwg.org/#concept-response-response">response</a>, except for its <a>body</a>.</li>
                        <li>If <var>response</var>'s body is non-null, run these substeps:
                          <ol>
                            <li>Let <var>reader</var> be the result of <a lt="get a reader">getting a reader</a> from <var>response</var>'s <a>body</a>'s <a>stream</a>.</li>
                            <li>Let <var>strategy</var> be an object created in <var>targetRealm</var>. The user agent may choose any object.</li>
                            <li>Let <var>pull</var> be an action that runs these subsubsteps:
                              <ol>
                                <li>Let <var>promise</var> be the result of <a lt="read a chunk from a ReadableStream">reading</a> a chunk from <var>response</var>'s <a>body</a>'s <a>stream</a> with <var>reader</var>.</li>
                                <li>When <var>promise</var> is fulfilled with an object whose <code>done</code> property is false and whose <code>value</code> property is a <code>Uint8Array</code> object, append the bytes represented by the <code>value</code> property to <var>bytes</var> and perform ! <a href="https://tc39.github.io/ecma262/#sec-detacharraybuffer">DetachArrayBuffer</a> with the <code>ArrayBuffer</code> object wrapped by the <code>value</code> property.</li>
                                <li>When <var>promise</var> is fulfilled with an object whose <code>done</code> property is true, set <var>end-of-body</var> to true.</li>
                                <li>When <var>promise</var> is fulfilled with a value that matches with neither of the above patterns, or <var>promise</var> is rejected, <a lt="error ReadableStream">error</a> <var>newStream</var> with a <code>TypeError</code>.</li>
                              </ol>
                            </li>
                            <li>Let <var>cancel</var> be an action that <a lt="cancel a ReadableStream">cancels</a> <var>response</var>'s <a>body</a>'s <a>stream</a> with <var>reader</var>.</li>
                            <li>Let <var>newStream</var> be the result of <a lt="construct a ReadableStream">constructing</a> a ReadableStream object with <var>strategy</var>, <var>pull</var> and <var>cancel</var> in <var>targetRealm</var>.</li>
                            <li>Set <var>potentialResponse</var>'s <a>body</a> to a new <a>body</a> whose <a>stream</a> is <var>newStream</var>.</li>
                            <li>Run these subsubsteps repeatedly <a>in parallel</a> while <var>done</var> is false:</li>
                              <ol>
                                <li>If <var>newStream</var> is <a>errored</a>, then set <var>done</var> to true.</li>
                                <li>Otherwise, if <var>bytes</var> is empty and <var>end-of-body</var> is true, then <a lt="close ReadableStream">close</a> <var>newStream</var> and set <var>done</var> to true.</li>
                                <li>Otherwise, if <var>bytes</var> is not empty, run these subsubsubsteps:
                                  <ol>
                                    <li>Let <var>chunk</var> be a subsequence of <var>bytes</var> starting from the beginning of <var>bytes</var>.</li>
                                    <li>Remove <var>chunk</var> from <var>bytes</var>.
                                    <li>Let <var>buffer</var> be an <code>ArrayBuffer</code> object created in <var>targetRealm</var> and containing <var>chunk</var>.
                                    <li><a lt="enqueue a chunk to ReadableStream">Enqueue</a> a <code>Uint8Array</code> object created in <var>targetRealm</var> and wrapping <var>buffer</var> to <var>newStream</var>.
                                  </ol>
                                </li>
                              </ol>
                            </li>
                          </ol>
                          <p class="note">These substeps are meant to produce the observable equivalent of "piping" <var>response</var>'s <a href="https://fetch.spec.whatwg.org/#concept-body-body">body</a>'s <a>stream</a> into <var>potentialResponse</var>.</p>
                        </li>
                        <li>Set the <a>potential response</a> to <var>potentialResponse</var>.</li>
                      </ol>
                    </li>
                  </ol>
                </li>
                <li>Else:
                  <ol>
                    <li>Set the <a href="#respond-with-error-flag">respond-with error flag</a>.</li>
                  </ol>
                  <p class="note">If the <a href="#respond-with-error-flag">respond-with error flag</a> is set, a <a>network error</a> is returned to <a>Fetch</a> through <a href="#on-fetch-request-algorithm">Handle Fetch</a> algorithm. (See the step 21.1.) Otherwise, the value <var>response</var> is returned to <a>Fetch</a> through <a href="#on-fetch-request-algorithm">Handle Fetch</a> algorithm. (See the step 22.1.)</p>
                </li>
              </ol>
            </li>
            <li>Unset the <a href="#wait-to-respond-flag">wait to respond flag</a>.</li>
          </ol>
        </li>
      </ol>
    </section>
  </section>

  <section dfn-for="ForeignFetchEvent">
    <h3 id="foreign-fetch-event-section">{{ForeignFetchEvent}}</h3>

    <pre class="idl">
      [Constructor(DOMString type, ForeignFetchEventInit eventInitDict), Exposed=ServiceWorker]
      interface ForeignFetchEvent : ExtendableEvent {
        [SameObject] readonly attribute Request request;
        readonly attribute USVString origin;

        void respondWith(Promise&lt;ForeignFetchResponse&gt; r);
      };

      dictionary ForeignFetchEventInit : ExtendableEventInit {
        required Request request;
        USVString origin = "null";
      };

      dictionary ForeignFetchResponse {
        required Response response;
        USVString origin;
        sequence&lt;ByteString&gt; headers;
      };
    </pre>

    <p><a href="#dfn-service-worker">Service workers</a> have a <a href="#dfn-functional-events">functional event</a> <code><a href="#service-worker-global-scope-foreignfetch-event">foreignfetch</a></code>. For <code><a href="#service-worker-global-scope-foreignfetch-event">foreignfetch</a></code> events, <a href="#dfn-service-worker">service workers</a> use the <code><dfn interface>ForeignFetchEvent</dfn></code> interface which extends the {{ExtendableEvent}} interface.</p>

    <p>Each event using {{ForeignFetchEvent}} interface has an associated <dfn>potential response</dfn> (a <a for="fetch">response</a>), initially set to null, an associated <dfn>origin</dfn> (a {{USVString}} or null), initially set to null, an associated <dfn>list of exposed headers</dfn> (whose element type is a byte string), initially set to an empty list, and the following associated flags that are initially unset:
      <ul>
        <li><dfn id="foreign-fetch-wait-to-respond-flag">wait to respond flag</dfn></li>
        <li><dfn id="foreign-fetch-respond-with-entered-flag">respond-with entered flag</dfn></li>
        <li><dfn id="foreign-fetch-respond-with-error-flag">respond-with error flag</dfn></li>
      </ul>
    </p>

    <section>
      <h4 id="foreign-fetch-event-request">{{ForeignFetchEvent/request|event.request}}</h4>

      <p>The <dfn attribute><code>request</code></dfn> attribute <em class="rfc2119" title="MUST">must</em> return the value it was initialized to.</p>
    </section>

    <section>
      <h4 id="foreign-fetch-event-origin">{{ForeignFetchEvent/origin|event.origin}}</h4>

      <p>The <dfn attribute><code>origin</code></dfn> attribute <em class="rfc2119" title="MUST">must</em> return the value it was initialized to.</p>
    </section>

    <section algorithm="foreign-fetch-event-respondwith">
      <h4 id="foreign-fetch-event-respondwith">{{ForeignFetchEvent/respondWith(r)|event.respondWith(r)}}</h4>

      <p class="note">Developers can set the argument <var>r</var> with either a <a>promise</a> that resolves with a {{Response}} object or a {{Response}} object (which is automatically cast to a promise). Otherwise, a <a>network error</a> is returned to <a>Fetch</a>. Renderer-side security checks about tainting for cross-origin content are tied to the types of <a>filtered responses</a> defined in <a>Fetch</a>.</p>

      <p><dfn method><code>respondWith(<var>r</var>)</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol link-for-hint="ForeignFetchEvent">
        <li>If the <a>dispatch flag</a> is unset, then:
          <ol>
            <li><a>Throw</a> an "{{InvalidStateError}}" exception.</li>
            <li>Abort these steps.</li>
          </ol>
        </li>
        <li>If the <a href="#respond-with-entered-flag">respond-with entered flag</a> is set, then:
          <ol>
            <li><a>Throw</a> an "{{InvalidStateError}}" exception.</li>
            <li>Abort these steps.</li>
          </ol>
        </li>
        <li>Add <var>r</var> to the <a>extend lifetime promises</a>.</li>
        <li>Set the <a>stop propagation flag</a> and <a>stop immediate propagation flag</a>.</li>
        <li>Set the <a href="#respond-with-entered-flag">respond-with entered flag</a>.</li>
        <li>Set the <a href="#wait-to-respond-flag">wait to respond flag</a>.</li>
        <li>Let <var>targetRealm</var> be the <a>relevant Realm</a> of the <a>context object</a>.
        <li>Run the following substeps <a>in parallel</a>:
          <ol>
            <li>Wait until <var>r</var> settles.</li>
            <li>If <var>r</var> rejected, then:
              <ol>
                <li>Set the <a href="#respond-with-error-flag">respond-with error flag</a>.</li>
              </ol>
            </li>
            <li>If <var>r</var> resolved with <var>response</var>, then:
              <ol>
                <li>If <var>response</var> is a {{ForeignFetchResponse}}, then:
                  <ol>
                    <li>Set the event's <a>origin</a> to <var>response</var>.{{ForeignFetchResponse/origin}}.</li>
                    <li>Set the event's <a>list of exposed headers</a> to <var>response</var>.{{ForeignFetchResponse/headers}}.</li>
                    <li>If <var>response</var>.{{ForeignFetchResponse/response}} is <a>disturbed</a> or <a>locked</a>, then:
                      <ol>
                        <li>Set the <a href="#respond-with-error-flag">respond-with error flag</a>.</li>
                      </ol>
                    </li>
                    <li>Else:
                      <ol>
                        <li>Let <var>bytes</var> be an empty byte sequence.
                        <li>Let <var>end-of-body</var> be false.
                        <li>Let <var>done</var> be false.
                        <li>Let <var>potentialResponse</var> be a copy of <var>response</var>.{{ForeignFetchResponse/response}}'s associated <a href="https://fetch.spec.whatwg.org/#concept-response-response">response</a>, except for its body.</li>
                        <li>If <var>response</var>.{{ForeignFetchResponse/response}}'s body is non-null, run these substeps:
                          <ol>
                            <li>Let <var>reader</var> be the result of <a lt="get a reader">getting a reader</a> from <var>response</var>.{{ForeignFetchResponse/response}}'s <a>body</a>'s <a>stream</a>.</li>
                            <li>Let <var>strategy</var> be an object created in <var>targetRealm</var>. The user agent may choose any object.</li>
                            <li>Let <var>pull</var> be an action that runs these subsubsteps:
                              <ol>
                                <li>Let <var>promise</var> be the result of <a lt="read a chunk from a ReadableStream">reading</a> a chunk from <var>response</var>.{{ForeignFetchResponse/response}}'s <a>body</a>'s <a>stream</a> with <var>reader</var>.</li>
                                <li>When <var>promise</var> is fulfilled with an object whose <code>done</code> property is false and whose <code>value</code> property is a <code>Uint8Array</code> object, append the bytes represented by the <code>value</code> property to <var>bytes</var> and perform ! <a href="https://tc39.github.io/ecma262/#sec-detacharraybuffer">DetachArrayBuffer</a> with the <code>ArrayBuffer</code> object wrapped by the <code>value</code> property.</li>
                                <li>When <var>promise</var> is fulfilled with an object whose <code>done</code> property is true, set <var>end-of-body</var> to true.</li>
                                <li>When <var>promise</var> is fulfilled with a value that matches with neither of the above patterns, or <var>promise</var> is rejected, <a lt="error ReadableStream">error</a> <var>newStream</var> with a <code>TypeError</code>.</li>
                              </ol>
                            </li>
                            <li>Let <var>cancel</var> be an action that <a lt="cancel a ReadableStream">cancels</a> <var>response</var>.{{ForeignFetchResponse/response}}'s <a>body</a>'s <a>stream</a> with <var>reader</var>.</li>
                            <li>Let <var>newStream</var> be the result of <a lt="construct a ReadableStream">constructing</a> a ReadableStream object with <var>strategy</var>, <var>pull</var> and <var>cancel</var> in <var>targetRealm</var>.</li>
                            <li>Set <var>potentialResponse</var>'s <a>body</a> to a new <a>body</a> whose <a>stream</a> is <var>newStream</var>.</li>
                            <li>Run these subsubsteps repeatedly <a>in parallel</a> while <var>done</var> is false:</li>
                              <ol>
                                <li>If <var>newStream</var> is <a>errored</a>, then set <var>done</var> to true.</li>
                                <li>Otherwise, if <var>bytes</var> is empty and <var>end-of-body</var> is true, then <a lt="close ReadableStream">close</a> <var>newStream</var> and set <var>done</var> to true.</li>
                                <li>Otherwise, if <var>bytes</var> is not empty, run these subsubsubsteps:
                                  <ol>
                                    <li>Let <var>chunk</var> be a subsequence of <var>bytes</var> starting from the beginning of <var>bytes</var>.</li>
                                    <li>Remove <var>chunk</var> from <var>bytes</var>.
                                    <li>Let <var>buffer</var> be an <code>ArrayBuffer</code> object created in <var>targetRealm</var> and containing <var>chunk</var>.
                                    <li><a lt="enqueue a chunk to ReadableStream">Enqueue</a> a <code>Uint8Array</code> object created in <var>targetRealm</var> and wrapping <var>buffer</var> to <var>newStream</var>.
                                  </ol>
                                </li>
                              </ol>
                            </li>
                          </ol>
                        </li>
                        <li>Set the <a>potential response</a> to <var>potentialResponse</var>.</li>
                      </ol>
                    </li>
                  </ol>
                </li>
                <li>Else:
                  <ol>
                    <li>Set the <a href="#respond-with-error-flag">respond-with error flag</a>.</li>
                  </ol>
                  <p class="note">If the <a href="#respond-with-error-flag">respond-with error flag</a> is set, a <a>network error</a> is returned to <a>Fetch</a> through [[#on-foreign-fetch-request-algorithm]] algorithm. (See the step 19.1.) Otherwise, a filtered version of <var>response</var> is returned to <a>Fetch</a> through [[#on-foreign-fetch-request-algorithm]] algorithm. (See the step 20.1.)</p>
                </li>
              </ol>
            </li>
            <li>Unset the <a href="#wait-to-respond-flag">wait to respond flag</a>.</li>
          </ol>
        </li>
      </ol>
    </section>
  </section>

  <section dfn-for="ExtendableMessageEvent">
    <h3 id="extendablemessage-event-section">{{ExtendableMessageEvent}}</h3>

    <pre class="idl">
      [Constructor(DOMString type, optional ExtendableMessageEventInit eventInitDict), Exposed=ServiceWorker]
      interface ExtendableMessageEvent : ExtendableEvent {
        readonly attribute any data;
        readonly attribute DOMString origin;
        readonly attribute DOMString lastEventId;
        [SameObject] readonly attribute (Client or ServiceWorker or MessagePort)? source;
        readonly attribute FrozenArray&lt;MessagePort&gt;? ports;
      };
    </pre>
    <pre class="idl" id="extendablemessage-event-init-dictionary">
      dictionary ExtendableMessageEventInit : ExtendableEventInit {
        any data;
        DOMString origin;
        DOMString lastEventId;
        (Client or ServiceWorker or MessagePort)? source;
        sequence&lt;MessagePort&gt;? ports;
      };
    </pre>

    <p><a href="#dfn-service-worker">Service workers</a> define the <a href="#extendable-event-waituntil-method">extendable</a> <a href="#service-worker-global-scope-message-event">message</a> event that extends the {{Window/message}} event defined in [[!HTML]] to allow extending the lifetime of the event. For the <a href="#service-worker-global-scope-message-event">message</a> event, <a href="#dfn-service-worker">service workers</a> use the <code><dfn interface id="extendablemessage-event-interface">ExtendableMessageEvent</dfn></code> interface which extends the {{ExtendableEvent}} interface.</p>

    <section>
      <h4 id="extendablemessage-event-data">{{ExtendableMessageEvent/data|event.data}}</h4>

      <p>The <dfn attribute id="extendablemessage-event-data-attribute">data</dfn> attribute <em class="rfc2119" title="MUST">must</em> return the value it was initialized to. When the object is created, this attribute <em class="rfc2119" title="MUST">must</em> be initialized to null. It represents the message being sent.</p>
    </section>

    <section>
      <h4 id="extendablemessage-event-origin">{{ExtendableMessageEvent/origin|event.origin}}</h4>

      <p>The <dfn attribute id="extendablemessage-event-origin-attribute">origin</dfn> attribute <em class="rfc2119" title="MUST">must</em> return the value it was initialized to. When the object is created, this attribute <em class="rfc2119" title="MUST">must</em> be initialized to the empty string. It represents the <a for="resource">origin</a> of the <a href="#dfn-service-worker-client">service worker client</a> that sent the message.</p>
    </section>

    <section>
      <h4 id="extendablemessage-event-lasteventid">{{ExtendableMessageEvent/lastEventId|event.lastEventId}}</h4>

      <p>The <dfn attribute id="extendablemessage-event-lasteventid-attribute">lastEventId</dfn> attribute <em class="rfc2119" title="MUST">must</em> return the value it was initialized to. When the object is created, this attribute <em class="rfc2119" title="MUST">must</em> be initialized to the empty string.</p>
    </section>

    <section>
      <h4 id="extendablemessage-event-source">{{ExtendableMessageEvent/source|event.source}}</h4>

      <p>The <dfn attribute id="extendablemessage-event-source-attribute">source</dfn> attribute <em class="rfc2119" title="MUST">must</em> return the value it was initialized to. When the object is created, this attribute <em class="rfc2119" title="MUST">must</em> be initialized to null. It represents the {{Client}} object from which the message is sent.</p>
    </section>

    <section>
      <h4 id="extendablemessage-event-ports">{{ExtendableMessageEvent/ports|event.ports}}</h4>

      <p>The <dfn attribute id="extendablemessage-event-ports-attribute">ports</dfn> attribute <em class="rfc2119" title="MUST">must</em> return the value it was initialized to. When the object is created, this attribute <em class="rfc2119" title="MUST">must</em> be initialized to null. It represents the {{MessagePort}} array being sent, if any.</p>
    </section>
  </section>

  <section>
    <h3 id="execution-context-events">Events</h3>

    <p>The following events are dispatched on <a href="#service-worker-global-scope-interface">ServiceWorkerGlobalScope</a> object:</p>

    <table class="data" dfn-for="ServiceWorkerGlobalScope">
      <thead>
        <tr>
          <th>Event name</th>
          <th>Interface</th>
          <th>Dispatched when&mldr;</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><dfn event id="service-worker-global-scope-install-event"><code>install</code></dfn></td>
          <td>{{InstallEvent}}</td>
          <td>[<a href="#dfn-lifecycle-events">Lifecycle event</a>] The <a href="#dfn-service-worker-global-scope-service-worker">service worker</a>'s <a href="#dfn-containing-service-worker-registration">containing service worker registration</a>'s <a href="#dfn-installing-worker">installing worker</a> changes. (See step 11.2 of the <a href="#installation-algorithm">Install</a> algorithm.)</td>
        </tr>
        <tr>
          <td><dfn event id="service-worker-global-scope-activate-event"><code>activate</code></dfn></td>
          <td>{{ExtendableEvent}}</td>
          <td>[<a href="#dfn-lifecycle-events">Lifecycle event</a>] The <a href="#dfn-service-worker-global-scope-service-worker">service worker</a>'s <a href="#dfn-containing-service-worker-registration">containing service worker registration</a>'s <a href="#dfn-active-worker">active worker</a> changes. (See step 12.2 of the <a href="#activation-algorithm">Activate</a> algorithm.)</td>
        </tr>
        <tr>
          <td><dfn event id="service-worker-global-scope-fetch-event"><code>fetch</code></dfn></td>
          <td>{{FetchEvent}}</td>
          <td>[<a href="#dfn-functional-events">Functional event</a>] The <a>http fetch</a> invokes <a href="#on-fetch-request-algorithm">Handle Fetch</a> with <var>request</var>. As a result of performing <a href="#on-fetch-request-algorithm">Handle Fetch</a>, the <a href="#dfn-service-worker-global-scope-service-worker">service worker</a> returns a <a for="fetch">response</a> to the <a>http fetch</a>. The <a for="fetch">response</a>, represented by a {{Response}} object, can be retrieved from a {{Cache}} object or directly from network using {{GlobalFetch/fetch(input, init)|self.fetch(input, init)}} method. (A custom {{Response}} object can be another option.)</td>
        </tr>
        <tr>
          <td><dfn event id="service-worker-global-scope-foreignfetch-event"><code>foreignfetch</code></dfn></td>
          <td>{{FetchEvent}}</td>
          <td>[<a href="#dfn-functional-events">Functional event</a>] The <a>http fetch</a> invokes [[#on-foreign-fetch-request-algorithm]] with <var>request</var>. As a result of performing [[#on-foreign-fetch-request-algorithm]], the <a for="ServiceWorkerGlobalScope">service worker</a> returns a <a for="fetch">response</a> to the <a>http fetch</a>. The <a for="fetch">response</a>, represented by a {{Response}} object, can be retrieved from a {{Cache}} object or directly from network using {{GlobalFetch/fetch(input, init)|self.fetch(input, init)}} method. (A custom {{Response}} object can be another option.)</td>
        </tr>
        <tr>
          <td><dfn event id="service-worker-global-scope-message-event"><code>message</code></dfn></td>
          <td>{{ExtendableMessageEvent}}</td>
          <td>When it receives a message.</td>
        </tr>
      </tbody>
    </table>
  </section>
</section>

<section>
  <h2 id="link-type-serviceworker">Link type "<code>serviceworker</code>"</h2>
  <p>The <dfn id="dfn-link-type-serviceworker" lt="serviceworker link type"><code>serviceworker</code></dfn> keyword may be used with <{link}> elements. This keyword creates an <a>external resource link</a> (<dfn id="dfn-serviceworker-link">serviceworker link</dfn>) that is used to declare a <a for="/">service worker registration</a> and its <a for="service worker registration">scope url</a>.</p>

  <section>
    <h3 id="link-element-processing">Processing</h3>

    <p>When a user agent that supports [[!RFC5988]] processes a <code>Link</code> header that contains a <a>serviceworker link</a>, the user agent <em class="rfc2119" title="SHOULD">should</em> run these steps:</p>

    <ol>
      <li>If the <code>Link</code> header has an "<code>anchor</code>" parameter, abort these steps.</li>
      <li>Let <var>contextURL</var> be the result of <a for="url">parsing</a> the <a>context IRI</a> of the <code>Link</code> header.</li>
      <li>If the result of running <a>Is origin potentially trustworthy</a> with the <a for="resource">origin</a> of <var>contextURL</var> is <code>Not Trusted</code>, abort these steps.</li>
      <li>Let <var>request</var> be the <a for="fetch">request</a> for which this header was received in the response.</li>
      <li>If <var>request</var>'s <a for="request">client</a> is not a <a>secure context</a>, abort these steps.</li>
      <li>Let <var>scriptURL</var> be the result of <a for="url">parsing</a> the <a>target IRI</a> of the <code>Link</code> header.</li>
      <li>Let <var>scopeURL</var> be the "<code>scope</code>" <a>target attribute</a> of the <code>Link</code> header, or null if no such attribute is present.</li>
      <li>Let <var>workerType</var> be the "<code>workertype</code>" <a>target attribute</a> of the <code>Link</code> header, or "<code>classic</code>" if no such attribute is present.</li>
      <li>If <var>workerType</var> is not a valid {{WorkerType}} value, abort these steps.</li>
      <li>Invoke [[#start-register-algorithm]] with <var>scopeURL</var>, <var>scriptURL</var>, a new <a>promise</a>, null, <var>contextURL</var> and <var>workerType</var>.</li>
    </ol>

    <p>When a <a>serviceworker link</a>'s <{link}> element is <a lt="in a document">inserted into a document</a>, a <a>serviceworker link</a> is created on a <{link}> element that is already <a>in a Document</a>, or the <{link/href}> or <{link/scope}> attributes of the <{link}> element of a <a>serviceworker link</a> is changed, the user agent <em class="rfc2119" title="SHOULD">should</em> run these steps:</p>

    <ol>
      <li>If the <{link/href}> attribute is the empty string, abort these steps.</li>
      <li>Let <var>client</var> be the document's <a for="ServiceWorkerContainer">service worker client</a>.</li>
      <li>If <var>client</var> is not a <a>secure context</a>, <a>queue a task</a> to <a>fire a simple event</a> named <code>error</code> at the <{link}> element, and abort these steps.</li>
      <li>Let <var>scriptURL</var> be the result of <a for="url">parsing</a> the <{link/href}> attribute with document's <a>document base URL</a>.</li>
      <li>Let <var>scopeURL</var> be the <{link/scope}> attribute, or null if the <{link/scope}> attribute is omitted.</li>
      <li>Let <var>workerType</var> be the <{link/workertype}> attribute, or "<code>classic</code>" if the <{link/workertype}> attribute is omitted.</li>
      <li>If <var>workerType</var> is not a valid {{WorkerType}} value, <a>queue a task</a> to <a>fire a simple event</a> named <code>error</code> at the <{link}> element, and abort these steps.</li>
      <li>Let <var>promise</var> be a new <a>promise</a>.</li>
      <li>Invoke [[#start-register-algorithm]] with <var>scopeURL</var>, <var>scriptURL</var>, <var>promise</var>, <var>client</var>, <var>client</var>'s <a>creation URL</a> and <var>workerType</var>.</li>
      <li>Run the following substeps <a>in parallel</a>:
        <ol>
          <li>Wait until <var>promise</var> settles.</li>
          <li>If <var>promise</var> rejected, <a>queue a task</a> to <a>fire a simple event</a> named <code>error</code> at the <{link}> element.</li>
          <li>If <var>promise</var> resolved, <a>queue a task</a> to <a>fire a simple event</a> named <code>load</code> at the <{link}> element.</li>
        </ol>
      </li>
    </ol>

    <p>The <a href="#dfn-serviceworker-link">serviceworker link</a> element <em class="rfc2119" title="MUST NOT">must not</em> <a href="https://html.spec.whatwg.org/multipage/syntax.html#delay-the-load-event">delay the load event</a> of the element's <a href="https://dom.spec.whatwg.org/#concept-node-document">node document</a>.</p>

    <div class="example">
      A resource being loaded with the following response header:
      <pre class="highlight">
        Link: &lt;/js/sw.js&gt;; rel="serviceworker"; scope="/"
      </pre>
      has more or less the same effect as a document being loaded in a secure context with the following <code>link</code> element:
      <pre class="lang-html">
        &lt;link rel="serviceworker" href="/js/sw.js" scope="/"&gt;
      </pre>
      which is more or less equivalent to the page containing javascript code like:
      <pre class="lang-js">
        navigator.serviceworker.register("/js/sw.js", { scope: "/" });
      </pre>
    </div>
  </section>

  <section>
    <h3 id="link-element-interface-section">Link element interface extensions</h3>

    <pre class="idl">
      partial interface HTMLLinkElement {
        [CEReactions] attribute USVString scope;
        [CEReactions] attribute WorkerType workerType;
      };
    </pre>

    <p>The <dfn attribute for=HTMLLinkElement id="link-scope-attribute">scope</dfn> IDL attribute must <a>reflect</a> the element's <dfn element-attr for="link">scope</dfn> content attribute.</p>

    <p>The <dfn attribute for=HTMLLinkElement id="link-workertype-attribute">workerType</dfn> IDL attribute must <a>reflect</a> the element's <dfn element-attr for="link">workertype</dfn> content attribute.</p>
  </section>
</section>

<section>
  <h2 id="cache-objects">Caches</h2>

  <p>To allow authors to fully manage their content caches for offline use, the {{Window}} and the {{WorkerGlobalScope}} provide the asynchronous caching methods that open and manipulate {{Cache}} objects. An <a for="resource">origin</a> can have multiple, named {{Cache}} objects, whose contents are entirely under the control of scripts. Caches are not shared across <a for="resource">origins</a>, and they are completely isolated from the browser's HTTP cache.</p>

  <section>
    <h3 id="cache-constructs">Constructs</h3>

    <p>A <dfn id="dfn-fetching-record">fetching record</dfn> is a <a>Record</a> {\[[key]], \[[value]]} where \[[key]] is a {{Request}} and \[[value]] is a {{Response}}.</p>
    <p>A <a href="#dfn-fetching-record">fetching record</a> has an associated <dfn id="dfn-incumbent-record">incumbent record</dfn> (a <a href="#dfn-fetching-record">fetching record</a>). It is initially set to null.</p>
    <p>A <dfn id="dfn-request-to-response-map">request to response map</dfn> is a <a>List</a> of <a href="#dfn-fetching-record">fetching records</a>.</p>

    <p>A <dfn id="dfn-name-to-cache-map">name to cache map</dfn> is a <a>List</a> of the <a>Record</a> {\[[key]], \[[value]]} where \[[key]] is a string that represents a name of the {{Cache}} object and \[[value]] is a {{Cache}} object.</p>

    <p>Each <a for="resource">origin</a> has an associated <a href="#dfn-name-to-cache-map">name to cache map</a>.</p>
  </section>

  <section>
    <h3 id="cache-lifetimes">Understanding Cache Lifetimes</h3>

    <p>The {{Cache}} instances are not part of the browser's HTTP cache. The {{Cache}} objects are exactly what authors have to manage themselves. The {{Cache}} objects do not get updated unless authors explicitly request them to be. The {{Cache}} objects do not expire unless authors delete the entries. The {{Cache}} objects do not disappear just because the <a href="#dfn-service-worker">service worker</a> script is updated. That is, caches are not updated automatically. Updates must be manually managed. This implies that authors should version their caches by name and make sure to use the caches only from the version of the <a href="#dfn-service-worker">service worker</a> that can safely operate on.</p>
  </section>

  <section>
    <h3 id="self-caches">{{WindowOrWorkerGlobalScope/caches|self.caches}}</h3>

    <pre class="idl">
      partial interface WindowOrWorkerGlobalScope {
        [SecureContext, SameObject] readonly attribute CacheStorage caches;
      };
    </pre>

    <section>
      <h4 id="global-caches">{{WindowOrWorkerGlobalScope/caches}}</h4>

      <p><dfn attribute for="WindowOrWorkerGlobalScope" id="global-caches-attribute"><code>caches</code></dfn> attribute <em class="rfc2119" title="MUST">must</em> return this object's associated {{CacheStorage}} object.</p>
    </section>
  </section>

  <section dfn-for="Cache">
    <h3 id="cache">{{Cache}}</h3>

    <pre class="idl">
      [SecureContext, Exposed=(Window,Worker)]
      interface Cache {
        [NewObject] Promise&lt;any&gt; match(RequestInfo request, optional CacheQueryOptions options);
        [NewObject] Promise&lt;sequence&lt;Response&gt;&gt; matchAll(optional RequestInfo request, optional CacheQueryOptions options);
        [NewObject] Promise&lt;void&gt; add(RequestInfo request);
        [NewObject] Promise&lt;void&gt; addAll(sequence&lt;RequestInfo&gt; requests);
        [NewObject] Promise&lt;void&gt; put(RequestInfo request, Response response);
        [NewObject] Promise&lt;boolean&gt; delete(RequestInfo request, optional CacheQueryOptions options);
        [NewObject] Promise&lt;sequence&lt;Request&gt;&gt; keys(optional RequestInfo request, optional CacheQueryOptions options);
      };
    </pre>
    <pre class="idl" id="cache-query-options-dictionary">
      dictionary CacheQueryOptions {
        boolean ignoreSearch = false;
        boolean ignoreMethod = false;
        boolean ignoreVary = false;
        DOMString cacheName;
      };
    </pre>
    <pre class="idl" id="cache-batch-operation-dictionary">
      dictionary CacheBatchOperation {
        DOMString type;
        Request request;
        Response response;
        CacheQueryOptions options;
      };
    </pre>

    <p>A <code><dfn interface id="cache-interface">Cache</a></code> object represents a <a href="#dfn-request-to-response-map">request to response map</a>. Multiple separate objects implementing the {{Cache}} interface across documents and workers can all be associated with the same <a href="#dfn-request-to-response-map">request to response map</a> simultaneously.</p>

    <p>{{Cache}} objects are always enumerable via {{WindowOrWorkerGlobalScope/caches|self.caches}} in insertion order (per <a lt="map objects">ECMAScript 6 Map objects</a>).</p>

    <section algorithm="cache-match">
      <h4 id="cache-match">{{Cache/match(request, options)}}</h4>

      <p><dfn method id="cache-match-method"><code>match(<var>request</var>, <var>options</var>)</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>Let <var>promise</var> be a new <a>promise</a>.</li>
        <li>Run these substeps <a>in parallel</a>:
          <ol>
            <li>Let <var>p</var> be the result of running the algorithm specified in {{Cache/matchAll(request, options)}} method with <var>request</var> and <var>options</var> as the arguments.</li>
            <li>Wait until <var>p</var> settles.</li>
            <li>If <var>p</var> rejects with an exception, then:
              <ol>
                <li>Reject <var>promise</var> with that exception.</li>
              </ol>
            </li>
            <li>Else if <var>p</var> resolves with an array, <var>responseArray</var>, then:
              <ol>
                <li>If <var>responseArray</var> is an empty array, then:
                  <ol>
                    <li>Resolve <var>promise</var> with undefined.</li>
                  </ol>
                </li>
                <li>Else:
                  <ol>
                    <li>Resolve <var>promise</var> with the first element of <var>responseArray</var>.</li>
                  </ol>
                </li>
              </ol>
            </li>
          </ol>
        </li>
        <li>Return <var>promise</var>.</li>
      </ol>
    </section>

    <section algorithm="cache-matchall">
      <h4 id="cache-matchall">{{Cache/matchAll(request, options)}}</h4>

      <p><dfn method for="Cache" id="cache-matchall-method"><code>matchAll(<var>request</var>, <var>options</var>)</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>Let <var>r</var> be null.</li>
        <li>If the optional argument <var>request</var> is not omitted, then:
          <ol>
            <li>If <var>request</var> is a {{Request}} object, then:
              <ol>
                <li>Set <var>r</var> to <var>request</var>'s <a for="request">request</a>.</li>
                <li>If <var>r</var>'s <a for="request">method</a> is not `<code>GET</code>` and <var>options</var>.<var>ignoreMethod</var> is false, return a <a>promise</a> resolved with an empty array.</li>
              </ol>
            </li>
            <li>Else if <var>request</var> is a string, then:
              <ol>
                <li>Set <var>r</var> to the associated <a for="request">request</a> of the result of invoking the initial value of {{Request}} as constructor with <var>request</var> as its argument. If this <a>throws</a> an exception, return a <a>promise</a> rejected with that exception.</li>
              </ol>
            </li>
          </ol>
        </li>
        <li>Let <var>promise</var> be a new <a>promise</a>.</li>
        <li>Run these substeps <a>in parallel</a>:
          <ol>
            <li>Let <var>responseArray</var> be an empty array.</li>
            <li>If the optional argument <var>request</var> is omitted, then:
              <ol>
                <li>For each <a href="#dfn-fetching-record">fetching record</a> <var>entry</var> of its <a href="#dfn-request-to-response-map">request to response map</a>, in key insertion order:
                  <ol>
                    <li>Add a  copy of <var>entry</var>.\[[value]] to <var>responseArray</var>.</li>
                  </ol>
                </li>
                <li>Resolve <var>promise</var> with <var>responseArray</var>.</li>
                <li>Abort these steps.</li>
              </ol>
            </li>
            <li>Else:
              <ol>
                <li>Let <var>entries</var> be the result of running <a href="#query-cache-algorithm">Query Cache</a> algorithm passing a {{Request}} object associated with <var>r</var> and <var>options</var> as the arguments.</li>
                <li>For each <var>entry</var> of <var>entries</var>:
                  <ol>
                    <li>Let <var>response</var> be null.</li>
                    <li>If the <a href="#dfn-incumbent-record">incumbent record</a> <var>incumbentRecord</var> of the corresponding <a href="#dfn-fetching-record">fetching record</a> <var>fetchingRecord</var> in <a href="#dfn-request-to-response-map">request to response map</a> is not null, set <var>response</var> to a copy of <var>incumbentRecord</var>.\[[value]].</li>
                    <li>Else, set <var>response</var> to a copy of <var>entry</var>[1].</li>
                    <li>Add <var>response</var> to <var>responseArray</var>.</li>
                  </ol>
                </li>
                <li>Resolve <var>promise</var> with <var>responseArray</var>.</li>
              </ol>
            </li>
          </ol>
        </li>
        <li>Return <var>promise</var>.</li>
      </ol>
    </section>

    <section algorithm="cache-add">
      <h4 id="cache-add">{{Cache/add(request)}}</h4>

      <p><dfn method id="cache-add-method"><code>add(<var>request</var>)</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>Let <var>requests</var> be an array containing only <var>request</var>.</li>
        <li>Set <var>responseArrayPromise</var> to the result of running the algorithm specified in {{Cache/addAll(requests)}} passing <var>requests</var> as the argument.</li>
        <li>Return the result of <a>transforming</a> <var>responseArrayPromise</var> with a fulfillment handler that returns undefined.</li>
      </ol>
    </section>

    <section algorithm="cache-addAll">
      <h4 id="cache-addAll">{{Cache/addAll(requests)}}</h4>

      <p><dfn method id="cache-addAll-method"><code>addAll(<var>requests</var>)</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>Let <var>responsePromiseArray</var> be an empty array.</li>
        <li>Let <var>requestArray</var> be an empty array.</li>
        <li>For each <var>request</var> whose type is {{Request}} in <var>requests</var>:
          <ol>
            <li>Let <var>r</var> be <var>request</var>'s <a for="request">request</a>.</li>
            <li>If <var>r</var>'s <a for="request">url</a>'s <a for="url">scheme</a> is not one of "<code>http</code>" and "<code>https</code>", or <var>r</var>'s <a for="request">method</a> is not `<code>GET</code>`, return a <a>promise</a> rejected with a <code>TypeError</code>.</li>
          </ol>
        </li>
        <li>For each <var>request</var> in <var>requests</var>:
          <ol>
            <li>Let <var>r</var> be the associated <a for="request">request</a> of the result of invoking the initial value of {{Request}} as constructor with <var>request</var> as its argument. If this <a>throws</a> an exception, return a <a>promise</a> rejected with that exception.</li>
            <li>If <var>r</var>'s <a for="request">url</a>'s <a for="url">scheme</a> is not one of "<code>http</code>" and "<code>https</code>", then:
              <ol>
                <li><a>Terminate</a> all the ongoing <a>fetches</a> initiated by <var>requests</var> with reason <em>fatal</em>.</li>
                <li>Break the loop.</li>
              </ol>
            </li>
            <li>Set <var>r</var>'s <a for="request">initiator</a> to "<code>fetch</code>" and <a for="request">destination</a> to "<code>subresource</code>".</li>
            <li>Add a {{Request}} object associated with <var>r</var> to <var>requestArray</var>.</li>
            <li>Let <var>responsePromise</var> be a new <a>promise</a>.</li>
            <li>Run the following substeps <a>in parallel</a>:
              <ul>
                <li><a>Fetch</a> <var>r</var>.</li>
                <li>To <a>process response</a> for <var>response</var>, run these substeps:
                  <ol>
                    <li>If <var>response</var>'s <a for="response">type</a> is <em>error</em>, or <var>response</var>'s <a>status</a> is not an <a>ok status</a>, reject <var>responsePromise</var> with a <code>TypeError</code>.</li>
                    <li>Else if <var>response</var>'s <a for="response">header list</a> contains a <a>header</a> <a for="header">named</a> `<code>Vary</code>`, then:
                      <ol>
                        <li>Let <var>varyHeaders</var> be the array containing the elements corresponding to the <a for="http">field-values</a> of the <a>Vary</a> header.</li>
                        <li>Let <var>matchAsterisk</var> be false.</li>
                        <li>For each <var>f</var> in <var>varyHeaders</var>:
                          <ol>
                            <li>If <var>f</var> matches "<code>*</code>", set <var>matchAsterisk</var> to true and break the loop.</li>
                          </ol>
                        </li>
                        <li>If <var>matchAsterisk</var> is true, reject <var>responsePromise</var> with a <code>TypeError</code>.</li>
                        <li>Else, resolve <var>responsePromise</var> with a new {{Response}} object associated with <var>response</var> and a new {{Headers}} object whose <a>guard</a> is "<code>immutable</code>".</li>
                      </ol>
                    </li>
                    <li>Else, resolve <var>responsePromise</var> with a new {{Response}} object associated with <var>response</var> and a new {{Headers}} object whose <a>guard</a> is "<code>immutable</code>".</li>
                  </ol>
                  <p class="note">This step ensures that the promise for this fetch resolves as soon as the response's headers become available.</p>
                </li>
                <li>To <a>process response body</a> for <var>response</var>, do nothing.</li>
                <li>To <a>process response end-of-file</a> for <var>response</var>, do nothing.</li>
              </ul>
            </li>
            <li>Add <var>responsePromise</var> to <var>responsePromiseArray</var>.</li>
          </ol>
        </li>
        <li>Let <var>p</var> be <a>waiting for all</a> of <var>responsePromiseArray</var>.</li>
        <li>Return the result of <a>transforming</a> <var>p</var> with a fulfillment handler that, when called with argument <var>responseArray</var>, performs the following substeps <a>in parallel</a>:
          <ol>
            <li>Let <var>operations</var> be an empty array.</li>
            <li>For each <var>response</var> in <var>responseArray</var> with the index <var>index</var>:
              <ol>
                <li>Let <var>o</var> be an empty object representing a {{CacheBatchOperation}} dictionary.</li>
                <li>Set the {{CacheBatchOperation/type}} dictionary member of <var>o</var> to "put".</li>
                <li>Set the {{CacheBatchOperation/request}} dictionary member of <var>o</var> to <var>requestArray</var>[<var>index</var>].</li>
                <li>Set the {{CacheBatchOperation/response}} dictionary member of <var>o</var> to <var>response</var>.</li>
                <li>Add <var>o</var> to <var>operations</var>.</li>
              </ol>
            </li>
            <li>Let <var>resultPromise</var> be the result of running <a href="#batch-cache-operations-algorithm">Batch Cache Operations</a> algorithm passing <var>operations</var> as the argument.</li>
            <li>Return the result of <a>transforming</a> <var>resultPromise</var>  with a fulfillment handler that, when called with argument <var>responses</var>, performs the following substeps <a>in parallel</a>:
              <ol>
                <li>Let <var>responseBodyPromiseArray</var> be an empty array.</li>
                <li>For each <var>response</var> in <var>responses</var>:
                  <ol>
                    <li>Let <var>responseBodyPromise</var> be a new <a>promise</a>.</li>
                    <li>Run the following substeps <a>in parallel</a>:
                      <ol>
                        <li>Wait for either end-of-file to have been pushed to <var>response</var>'s associated <a for="response">response</a> <var>r</var>'s <a for="response">body</a> or for <var>r</var> to have a <a for="response">termination reason</a>.</li>
                        <li>If <var>r</var> had a <a for="response">termination reason</a>, then:
                          <ol>
                            <li>If the <a href="#dfn-incumbent-record">incumbent record</a> <var>incumbentRecord</var> of the corresponding <a href="#dfn-fetching-record">fetching record</a> <var>fetchingRecord</var> in <a href="#dfn-request-to-response-map">request to response map</a> is not null, then:
                              <ol>
                                <li>Set <var>fetchingRecord</var> in <a href="#dfn-request-to-response-map">request to response map</a> to the copy of <var>incumbentRecord</var>.</li>
                              </ol>
                            </li>
                            <li>Else:
                              <ol>
                                <li>Delete <var>fetchingRecord</var> from <a href="#dfn-request-to-response-map">request to response map</a>.</li>
                              </ol>
                            </li>
                            <li>Reject <var>responseBodyPromise</var> with a <code>TypeError</code>.</li>
                          </ol>
                        </li>
                        <li>Else:
                          <ol>
                            <li>Set the <a href="#dfn-incumbent-record">incumbent record</a> of the corresponding <a href="#dfn-fetching-record">fetching record</a> <var>fetchingRecord</var> in <a href="#dfn-request-to-response-map">request to response map</a> to the copy of <var>fetchingRecord</var>.</li>
                            <li>Let <var>invalidRecords</var> be the result of running <a href="#query-cache-algorithm">Query Cache</a> algorithm passing <var>fetchingRecord</var>.\[[key]] as the argument.</li>
                            <li>For each <var>invalidRecord</var> in <var>invalidRecords</var>:
                              <ol>
                                <li>If <var>invalidRecord</var> is not <var>fetchingRecord</var>, delete it from <a href="#dfn-request-to-response-map">request to response map</a>.</li>
                              </ol>
                            </li>
                            <li>Resolve <var>responseBodyPromise</var> with <var>response</var>.</li>
                          </ol>
                        </li>
                      </ol>
                    </li>
                    <li>Add <var>responseBodyPromise</var> to <var>responseBodyPromiseArray</var>.</li>
                  </ol>
                </li>
                <li>Let <var>q</var> be <a>waiting for all</a> of <var>responseBodyPromiseArray</var>.</li>
                <li>Return the result of <a>transforming</a> <var>q</var>  with a fulfillment handler that returns undefined.</li>
              </ol>
            </li>
          </ol>
        </li>
      </ol>
    </section>

    <section algorithm="cache-put">
      <h4 id="cache-put">{{Cache/put(request, response)}}</h4>

      <p><dfn method id="cache-put-method"><code>put(<var>request</var>, <var>response</var>)</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>Let <var>r</var> be null.</li>
        <li>If <var>request</var> is a {{Request}} object, then:
          <ol>
            <li>Set <var>r</var> to <var>request</var>'s <a for="request">request</a>.</li>
            <li>If <var>r</var>'s <a for="request">url</a>'s <a for="url">scheme</a> is not one of "<code>http</code>" and "<code>https</code>", or <var>r</var>'s <a for="request">method</a> is not `<code>GET</code>`, return a <a>promise</a> rejected with a <code>TypeError</code>.</li>
          </ol>
        </li>
        <li>Else if <var>request</var> is a string, then:
          <ol>
            <li>Set <var>r</var> to the associated <a for="request">request</a> of the result of invoking the initial value of {{Request}} as constructor with <var>request</var> as its argument. If this <a>throws</a> an exception, return a <a>promise</a> rejected with that exception.</li>
            <li>If <var>r</var>'s <a for="request">url</a>'s <a for="url">scheme</a> is not one of "<code>http</code>" and "<code>https</code>", return a <a>promise</a> rejected with a <code>TypeError</code>.</li>
          </ol>
        </li>
        <li>If <var>response</var>'s associated <a for="response">response</a>'s <a for="response">header list</a> contains a <a>header</a> <a for="header">named</a> `<code>Vary</code>`, then:
          <ol>
            <li>Let <var>varyHeaders</var> be the array containing the elements corresponding to the <a for="http">field-values</a> of the <a>Vary</a> header.</li>
            <li>For each <var>f</var> in <var>varyHeaders</var>:
              <ol>
                <li>If <var>f</var> matches "<code>*</code>", return a <a>promise</a> rejected with a <code>TypeError</code>.</li>
              </ol>
            </li>
          </ol>
        </li>
        <li>If <var>response</var> is <a>disturbed</a> or <a>locked</a>, return a <a>promise</a> rejected with a <code>TypeError</code>.</li>
        <li>Let <var>newResponse</var> be a new {{Response}} object associated with <var>response</var>'s associated <a href="https://fetch.spec.whatwg.org/#concept-response-response">response</a> and a new {{Headers}} object whose <a>guard</a> is <var>response</var>'s {{Headers}}' <a>guard</a>.</li>
        <li>If <var>response</var>'s body is non-null, run these substeps:
          <ol>
            <li>Let <var>dummyStream</var> be an <a>empty</a> <a>ReadableStream</a> object.</li>
            <li>Set <var>response</var>'s <a href="https://fetch.spec.whatwg.org/#concept-body-body">body</a> to a new <a>body</a> whose <a>stream</a> is <var>dummyStream</var>.</li>
            <li>Let <var>reader</var> be the result of <a lt="get a reader">getting a reader</a> from <var>dummyStream</var>.</li>
            <li><a>Read all bytes</a> from <var>dummyStream</var> with <var>reader</var>.</li>
          </ol>
        </li>
        <li>Let <var>operations</var> be an empty array.</li>
        <li>Let <var>o</var> be an empty object representing a {{CacheBatchOperation}} dictionary.</li>
        <li>Set the {{CacheBatchOperation/type}} dictionary member of <var>o</var> to "put".</li>
        <li>Set the {{CacheBatchOperation/request}} dictionary member of <var>o</var> to a {{Request}} object associated with <var>r</var>.</li>
        <li>Set the {{CacheBatchOperation/response}} dictionary member of <var>o</var> to <var>newResponse</var>.</li>
        <li>Add <var>o</var> to <var>operations</var>.</li>
        <li>Let <var>resultPromise</var> be the result of running <a href="#batch-cache-operations-algorithm">Batch Cache Operations</a> passing <var>operations</var> as the argument.</li>
        <li>Return the result of <a>transforming</a> <var>resultPromise</var> with a fulfillment handler that, when called with argument <var>responses</var>, performs the following substeps <a>in parallel</a>:
          <ol>
            <li>Wait for either end-of-file to have been pushed to <var>responses</var>[0]'s associated <a for="response">response</a> <var>r</var>'s <a for="response">body</a> or for <var>r</var> to have a <a for="response">termination reason</a>.</li>
            <li>If <var>r</var> had a <a for="response">termination reason</a>, then:
              <ol>
                <li>If the <a href="#dfn-incumbent-record">incumbent record</a> <var>incumbentRecord</var> of the corresponding <a href="#dfn-fetching-record">fetching record</a> <var>fetchingRecord</var> in <a href="#dfn-request-to-response-map">request to response map</a> is not null, then:
                  <ol>
                    <li>Set <var>fetchingRecord</var> in <a href="#dfn-request-to-response-map">request to response map</a> to the copy of <var>incumbentRecord</var>.</li>
                  </ol>
                </li>
                <li>Else:
                  <ol>
                    <li>Delete <var>fetchingRecord</var> from <a href="#dfn-request-to-response-map">request to response map</a>.</li>
                  </ol>
                </li>
                <li><a>Throw</a> a <code>TypeError</code>.</li>
              </ol>
            </li>
            <li>Else:
              <ol>
                <li>Set the <a href="#dfn-incumbent-record">incumbent record</a> of the corresponding <a href="#dfn-fetching-record">fetching record</a> <var>fetchingRecord</var> in <a href="#dfn-request-to-response-map">request to response map</a> to the copy of <var>fetchingRecord</var>.</li>
                <li>Let <var>invalidRecords</var> be the result of running <a href="#query-cache-algorithm">Query Cache</a> algorithm passing <var>fetchingRecord</var>.\[[key]] as the argument.</li>
                <li>For each <var>invalidRecord</var> in <var>invalidRecords</var>:
                  <ol>
                    <li>If <var>invalidRecord</var> is not <var>fetchingRecord</var>, delete it from <a href="#dfn-request-to-response-map">request to response map</a>.</li>
                  </ol>
                </li>
                <li>Return undefined.</li>
              </ol>
            </li>
          </ol>
        </li>
      </ol>
    </section>

    <section algorithm="cache-delete">
      <h4 id="cache-delete">{{Cache/delete(request, options)}}</h4>

      <p><dfn method id="cache-delete-method"><code>delete(<var>request</var>, <var>options</var>)</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>Let <var>r</var> be null.</li>
        <li>If <var>request</var> is a {{Request}} object, then:
          <ol>
            <li>Set <var>r</var> to <var>request</var>'s <a for="request">request</a>.</li>
            <li>If <var>r</var>'s <a for="request">method</a> is not `<code>GET</code>` and <var>options</var>.<var>ignoreMethod</var> is false, return a <a>promise</a> resolved with false.</li>
          </ol>
        </li>
        <li>Else if <var>request</var> is a string, then:
          <ol>
            <li>Set <var>r</var> to the associated <a for="request">request</a> of the result of invoking the initial value of {{Request}} as constructor with <var>request</var> as its argument. If this <a>throws</a> an exception, return a <a>promise</a> rejected with that exception.</li>
          </ol>
        </li>
        <li>Let <var>operations</var> be an empty array.</li>
        <li>Let <var>o</var> be an empty object representing a {{CacheBatchOperation}} dictionary.</li>
        <li>Set the {{CacheBatchOperation/type}} dictionary member of <var>o</var> to "delete".</li>
        <li>Set the {{CacheBatchOperation/request}} dictionary member of <var>o</var> to a {{Request}} object associated with <var>r</var>.</li>
        <li>Set the {{CacheBatchOperation/options}} dictionary member of <var>o</var> to <var>options</var>.</li>
        <li>Add <var>o</var> to <var>operations</var>.</li>
        <li>Let <var>resultPromise</var> be the result of running <a href="#batch-cache-operations-algorithm">Batch Cache Operations</a> passing <var>operations</var> as the argument.</li>
        <li>Return the result of <a>transforming</a> <var>resultPromise</var> with a fulfillment handler, when called with argument <var>responseArray</var>, performs the following substeps <a>in parallel</a>:
          <ol>
            <li>If <var>responseArray</var> is not null, return true.</li>
            <li>Else, return false.</li>
          </ol>
        </li>
      </ol>
    </section>

    <section algorithm="cache-keys">
      <h4 id="cache-keys">{{Cache/keys(request, options)}}</h4>

      <p><dfn method id="cache-keys-method"><code>keys(<var>request</var>, <var>options</var>)</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>Let <var>promise</var> be a new <a>promise</a>.</li>
        <li>Run these substeps <a>in parallel</a>:
          <ol>
            <li>Let <var>resultArray</var> be an empty array.</li>
            <li>If the optional argument <var>request</var> is omitted, then:
              <ol>
                <li>For each <a href="#dfn-fetching-record">fetching record</a> <var>entry</var> of its <a href="#dfn-request-to-response-map">request to response map</a>, in key insertion order:
                  <ol>
                    <li>Add <var>entry</var>.\[[key]] to <var>resultArray</var>.</li>
                  </ol>
                </li>
              </ol>
            </li>
            <li>Else:
              <ol>
                <li>Let <var>r</var> be null.</li>
                <li>If <var>request</var> is a {{Request}} object, then:
                  <ol>
                    <li>Set <var>r</var> to <var>request</var>'s <a for="request">request</a>.</li>
                    <li>If <var>r</var>'s <a for="request">method</a> is not `<code>GET</code>` and <var>options</var>.<var>ignoreMethod</var> is false, resolve <var>promise</var> with an empty array.</li>
                  </ol>
                </li>
                <li>Else if <var>request</var> is a string, then:
                  <ol>
                    <li>Set <var>r</var> to the associated <a for="request">request</a> of the result of invoking the initial value of {{Request}} as constructor with <var>request</var> as its argument. If this <a>throws</a> an exception, return a <a>promise</a> rejected with that exception.</li>
                  </ol>
                </li>
                <li>Let <var>requestResponseArray</var> be the result of running <a href="#query-cache-algorithm">Query Cache</a> algorithm passing a {{Request}} object that represents <var>r</var> and <var>options</var> as the arguments.</li>
                <li>For each <var>requestResponse</var> in <var>requestResponseArray</var>:
                  <ol>
                    <li>Add <var>requestResponse</var>[0] to <var>resultArray</var>.</li>
                  </ol>
                </li>
              </ol>
            </li>
            <li>Resolve <var>promise</var> with <var>resultArray</var>.</li>
          </ol>
        </li>
        <li>Return <var>promise</var>.</li>
      </ol>
    </section>
  </section>

  <section dfn-for="CacheStorage">
    <h3 id="cache-storage">{{CacheStorage}}</h3>

    <pre class="idl">
      [SecureContext, Exposed=(Window,Worker)]
      interface CacheStorage {
        [NewObject] Promise&lt;any&gt; match(RequestInfo request, optional CacheQueryOptions options);
        [NewObject] Promise&lt;boolean&gt; has(DOMString cacheName);
        [NewObject] Promise&lt;Cache&gt; open(DOMString cacheName);
        [NewObject] Promise&lt;boolean&gt; delete(DOMString cacheName);
        [NewObject] Promise&lt;sequence&lt;DOMString&gt;&gt; keys();
      };
    </pre>
<!--FIXME(jungkees): set method is not entirely dropped yet. Promise&lt;any&gt; set(DOMString key, Cache val);-->

    <p class="note">{{CacheStorage}} interface is designed to largely conform to <a lt="map objects">ECMAScript 6 Map objects</a> but entirely async, and with additional convenience methods. The methods, <code>clear</code>, <code>forEach</code>, <code>entries</code> and <code>values</code>, are intentionally excluded from the scope of the first version resorting to the ongoing discussion about the async iteration by TC39.</p>

    <p>The user agent <em class="rfc2119" title="MUST">must</em> create a {{CacheStorage}} object when a {{Window}} object or a {{WorkerGlobalScope}} object is created and associate it with that object.</p>

    <p>A <code><dfn interface id="cache-storage-interface">CacheStorage</dfn></code> object represents a <a href="#dfn-name-to-cache-map">name to cache map</a> of its associated <a>global object</a>'s <a>environment settings object</a>'s <a for="resource">origin</a>. Multiple separate objects implementing the {{CacheStorage}} interface across documents and workers can all be associated with the same <a href="#dfn-name-to-cache-map">name to cache map</a> simultaneously.</p>

    <section algorithm="cache-storage-match">
      <h4 id="cache-storage-match">{{CacheStorage/match(request, options)}}</h4>

      <p><dfn method id="cache-storage-match-method"><code>match(<var>request</var>, <var>options</var>)</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>If <var>options</var>.{{CacheQueryOptions/cacheName}} is <a>present</a>, then:
          <ol>
            <li>Return a new <a>promise</a> <var>p</var> and run the following substeps <a>in parallel</a>:
              <ol>
                <li>For each <a>Record</a> {\[[key]], \[[value]]} <var>entry</var> of its <a href="#dfn-name-to-cache-map">name to cache map</a>, in key insertion order:
                  <ol>
                    <li>If <var>options</var>.{{CacheQueryOptions/cacheName}} matches <var>entry</var>.\[[key]], then:
                      <ol>
                        <li>Resolve <var>p</var> with the result of running the algorithm specified in {{Cache/match(request, options)}} method of {{Cache}} interface with <var>request</var> and <var>options</var> as the arguments (providing <var>entry</var>.\[[value]] as thisArgument to the <a>\[[Call]]</a> internal method of {{Cache/match(request, options)}}.)</li>
                        <li>Abort these steps.</li>
                      </ol>
                    </li>
                  </ol>
                </li>
                <li>Resolve <var>p</var> with undefined.</li>
              </ol>
            </li>
          </ol>
        </li>
        <li>Else:
          <ol>
            <li>Let <var>p</var> be a <a>promise</a> resolved with undefined.</li>
            <li>For each <a>Record</a> {\[[key]], \[[value]]} <var>entry</var> of its <a href="#dfn-name-to-cache-map">name to cache map</a>, in key insertion order:
              <ol>
                <li>Set <var>p</var> to the result of <a>transforming</a> itself with a fulfillment handler that, when called with argument <var>v</var>, performs the following substeps <a>in parallel</a>:
                  <ol>
                    <li>If <var>v</var> is not undefined, return <var>v</var>.</li>
                    <li>Return the result of running the algorithm specified in {{Cache/match(request, options)}} method of {{Cache}} interface with <var>request</var> and <var>options</var> as the arguments (providing <var>entry</var>.\[[value]] as thisArgument to the <a>\[[Call]]</a> internal method of {{Cache/match(request, options)}}.)</li>
                  </ol>
                </li>
              </ol>
            </li>
            <li>Return <var>p</var>.</li>
          </ol>
        </li>
      </ol>
    </section>

    <section algorithm="cache-storage-has">
      <h4 id="cache-storage-has">{{CacheStorage/has(cacheName)}}</h4>

      <p><dfn method id="cache-storage-has-method"><code>has(<var>cacheName</var>)</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>Return a <a>promise</a> <var>p</var> resolved with the result of running the following substeps:
          <ol>
            <li>For each <a>Record</a> {\[[key]], \[[value]]} <var>entry</var> of its <a href="#dfn-name-to-cache-map">name to cache map</a>, in key insertion order:
              <ol>
                <li>If <var>cacheName</var> matches <var>entry</var>.\[[key]], then:
                  <ol>
                    <li>Return true.</li>
                  </ol>
                </li>
              </ol>
            </li>
            <li>Return false.</li>
          </ol>
        </li>
      </ol>
    </section>

    <section algorithm="cache-storage-open">
      <h4 id="cache-storage-open">{{CacheStorage/open(cacheName)}}</h4>

      <p><dfn method id="cache-storage-open-method"><code>open(<var>cacheName</var>)</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>Let <var>p</var> be a new <a>promise</a>.</li>
        <li>Run the following substeps:
          <ol>
            <li>For each <a>Record</a> {\[[key]], \[[value]]} <var>entry</var> of its <a href="#dfn-name-to-cache-map">name to cache map</a>, in key insertion order:
              <ol>
                <li>If <var>cacheName</var> matches <var>entry</var>.\[[key]], then:
                  <ol>
                    <li>Resolve <var>p</var> with a new {{Cache}} object which is a copy of <var>entry</var>.\[[value]].</li>
                    <li>Abort these steps.</li>
                  </ol>
                </li>
              </ol>
            </li>
            <li>Let <var>cache</var> be a new {{Cache}} object.</li>
            <li>Set a newly-created <a>Record</a> {\[[key]]: <var>cacheName</var>, \[[value]]: <var>cache</var>} to <a href="#dfn-name-to-cache-map">name to cache map</a>. If this cache write operation failed due to exceeding the granted quota limit, reject <var>p</var> with a "{{QuotaExceededError}}" exception and abort these steps.</li>
            <li>Resolve <var>p</var> with <var>cache</var>.</li>
          </ol>
        </li>
        <li>Return <var>p</var>.</li>
      </ol>
    </section>

    <section algorithm="cache-storage-delete">
      <h4 id="cache-storage-delete">{{CacheStorage/delete(cacheName)}}</h4>

      <p><dfn method id="cache-storage-delete-method"><code>delete(<var>cacheName</var>)</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <ol>
        <li>Let <var>p</var> be the result of running the algorithm specified in {{CacheStorage/has(cacheName)}} method with <var>cacheName</var> as the argument.</li>
        <li>Return the result of <a>transforming</a> <var>p</var> with a fulfillment handler that, when called with argument <var>cacheExists</var>, performs the following substeps <a>in parallel</a>:
          <ol>
            <li>If <var>cacheExists</var> is true, then:
              <ol>
                <li>Delete a <a>Record</a> {\[[key]], \[[value]]} <var>entry</var> from its <a href="#dfn-name-to-cache-map">name to cache map</a> where <var>cacheName</var> matches entry.\[[key]].</li>
                <li>Return true.</li>
                <li>Abort these steps.</li>
              </ol>
              <p class="note">After this step, the existing DOM objects (i.e. the currently referenced Cache, Request, and Response objects) should remain functional.</p>
            </li>
            <li>Else:
              <ol>
                <li>Return false.</li>
              </ol>
            </li>
          </ol>
        </li>
      </ol>
    </section>

    <section algorithm="cache-storage-keys">
      <h4 id="cache-storage-keys">{{CacheStorage/keys()}}</h4>

      <p><dfn method id="cache-storage-keys-method"><code>keys()</code></dfn> method <em class="rfc2119" title="MUST">must</em> run these steps:</p>

      <p class="note">The promise returned from this method resolves with the sequence of keys, cache names in DOMString, in insertion order.</p>

      <ol>
        <li>Let <var>resultArray</var> be an empty array.</li>
        <li>Return a <a>promise</a> <var>p</var> resolved with the result of running the following substeps:
          <ol>
            <li>For each <a>Record</a> {\[[key]], \[[value]]} <var>entry</var> of its <a href="#dfn-name-to-cache-map">name to cache map</a>, in key insertion order:
              <ol>
                <li>Add <var>entry</var>.\[[key]] to <var>resultArray</var>.</li>
              </ol>
            </li>
            <li>Return <var>resultArray</var>.</li>
          </ol>
        </li>
      </ol>
    </section>
  </section>
</section>

<section>
  <h2 id="security-considerations">Security Considerations</h2>

  <section>
    <h3 id="secure-context">Secure Context</h3>

    <p><a href="#dfn-service-worker">Service workers</a> <em class="rfc2119" title="MUST">must</em> execute in <a>secure contexts</a>. <a href="#dfn-service-worker-client">Service worker clients</a> <em class="rfc2119" title="MUST">must</em> also be <a>secure contexts</a> to register a <a href="#dfn-service-worker-registration">service worker registration</a>, to get access to the <a href="#dfn-service-worker-registration">service worker registrations</a> and the <a href="#dfn-service-worker">service workers</a>, to do messaging with the <a href="#dfn-service-worker">service workers</a>, and to be manipulated by the <a href="#dfn-service-worker">service workers</a>. This effectively means that <a href="#dfn-service-worker">service workers</a> and their <a href="#dfn-service-worker-client">service worker clients</a> <em class="rfc2119" title="SHOULD">should</em> be hosted over HTTPS. A user agent <em class="rfc2119" title="MAY">may</em> allow <code>localhost</code>, <code>127.0.0.0/8</code>, and <code>::1/128</code> for development purpose. (Note that they may still be <a>secure contexts</a>.) The primary reason for this restriction is to protect users from the <a>risks associated with insecure contexts</a>.</p>
  </section>

  <section>
    <h3 id="content-security-policy">Content Security Policy</h3>

    <p>Whenever a user agent invokes <a href="#run-service-worker-algorithm">Run Service Worker</a> algorithm with a <a href="#dfn-service-worker">service worker</a> <var>serviceWorker</var>:
      <ul>
        <li>If <var>serviceWorker</var>'s <a href="#dfn-script-resource">script resource</a> was delivered with a <code>Content-Security-Policy</code> HTTP header containing the value <var>policy</var>, the user agent <em class="rfc2119" title="MUST">must</em> <a>enforce</a> <var>policy</var> for <var>serviceWorker</var>.</li>
        <li>If <var>serviceWorker</var>'s <a href="#dfn-script-resource">script resource</a> was delivered with a <code>Content-Security-Policy-Report-Only</code> HTTP header containing the value <var>policy</var>, the user agent <em class="rfc2119" title="MUST">must</em> <a>monitor</a> <var>policy</var> for <var>serviceWorker</var>.</li>
      </ul>
    </p>
    <p>The primary reason for this restriction is to mitigate a broad class of content injection vulnerabilities, such as cross-site scripting (XSS).</p>
  </section>

  <section>
    <h3 id="origin-relativity">Origin Relativity</h3>

    <section>
      <h4 id="origin-restriction">Origin restriction</h4>

      <em>This section is non-normative.</em>

      <p>A <a href="#dfn-service-worker">Service worker</a> executes in the registering <a href="#dfn-service-worker-client">service worker client</a>'s <a for="resource">origin</a>. One of the advanced concerns that major applications would encounter is whether they can be hosted from a CDN. By definition, these are servers in other places, often on other <a for="resource">origins</a>. Therefore, <a href="#dfn-service-worker">service workers</a> cannot be hosted on CDNs. But they can include resources via <a href="#importscripts-method">importScripts()</a>. The reason for this restriction is that <a href="#dfn-service-worker">service workers</a> create the opportunity for a bad actor to turn a bad day into a bad eternity.</p>
    </section>

    <section>
      <h4 id="importscripts">{{WorkerGlobalScope/importScripts(urls)}}</h4>

      <p>When the <dfn method for="ServiceWorkerGlobalScope" id="importscripts-method"><code>importScripts(<var>urls</var>)</code></dfn> method is called on a {{ServiceWorkerGlobalScope}} object, the user agent <em class="rfc2119" title="MUST">must</em> <a>import scripts into worker global scope</a>, given this {{ServiceWorkerGlobalScope}} object and <var>urls</var>, and with the following steps to <a for="fetching scripts">perform the fetch</a> given the <a for="fetch">request</a> <var>request</var>:</p>

      <ol>
        <li>Let <var>serviceWorker</var> be <var>request</var>'s <a for="request">client</a>'s <a>global object</a>'s <a href="#dfn-service-worker-global-scope-service-worker">service worker</a>.</li>
        <li>If <var>serviceWorker</var>'s <a href="#dfn-imported-scripts-updated-flag">imported scripts updated flag</a> is unset, then:
          <ol>
            <li>Let <var>response</var> be the result of <a lt="fetch">fetching</a> <var>request</var>.</li>
            <li>If <var>response</var>'s <a>unsafe response</a>'s <a for="response">type</a> is not "<code>error</code>", and <var>response</var>'s <a for="response">status</a> is an <a>ok status</a>, then:
              <ol>
                <li>If there exists a corresponding Record <var>record</var> for <var>request</var>'s <a for="request">url</a> in <var>serviceWorker</var>'s <a href="#dfn-script-resource-map">script resource map</a>, set <var>record</var>.\[[value]] to <var>response</var>.</li>
                <li>Else, set a newly-created Record {\[[key]]: <var>url</var>, \[[value]]: <var>response</var>} to <var>serviceWorker</var>'s <a href="#dfn-script-resource-map">script resource map</a>.</li>
              </ol>
            </li>
            <li>Return <var>response</var>.
          </ol>
        </li>
        <li>Else:
          <ol>
            <li>If there exists a corresponding Record <var>record</var> for <var>url</var> in <var>serviceWorker</var>'s <a href="#dfn-script-resource-map">script resource map</a>, return <var>record</var>.\[[value]].</li>
            <li>Else, return a <a>network error</a>.</li>
          </ol>
        </li>
      </ol>
    </section>
  </section>

  <section>
    <h3 id="cross-origin-resources">Cross-Origin Resources and CORS</h3>

    <em>This section is non-normative.</em>

    <p>Applications tend to cache items that come from a CDN or other <a for="resource">origin</a>. It is possible to request many of them directly using <code>&lt;script&gt;</code>, <code>&lt;img&gt;</code>, <code>&lt;video&gt;</code> and <code>&lt;link&gt;</code> elements. It would be hugely limiting if this sort of runtime collaboration broke when offline. Similarly, it is possible to <a>fetch</a> many sorts of off-<a for="resource">origin</a> resources when appropriate CORS headers are set.</p>
    <p><a href="#dfn-service-worker">Service workers</a> enable this by allowing {{Cache|Caches}} to <a>fetch</a> and cache off-origin items. Some restrictions apply, however. First, unlike same-origin resources which are managed in the {{Cache}} as {{Response}} objects whose corresponding <a for="response">responses</a> are <a>basic filtered response</a>, the objects stored are {{Response}} objects whose corresponding <a for="response">responses</a> are either <a>CORS filtered responses</a> or <a>opaque filtered responses</a>. They can be passed to {{FetchEvent/respondWith(r)|event.respondWith(r)}} method in the same manner as the {{Response}} objects whose corresponding <a for="response">responses</a> are <a>basic filtered responses</a>, but cannot be meaningfully created programmatically. These limitations are necessary to preserve the security invariants of the platform. Allowing {{Cache|Caches}} to store them allows applications to avoid re-architecting in most cases.</p>
  </section>

  <section>
    <h3 id="implementer-concerns">Implementer Concerns</h3>

    <em>This section is non-normative.</em>

    <p>The implementers are encouraged to note:
      <ul>
        <li>Plug-ins should not load via <a href="#dfn-service-worker">service workers</a>. As plug-ins may get their security origins from their own urls, the embedding <a href="#dfn-service-worker">service worker</a> cannot handle it. For this reason, the <a href="#on-fetch-request-algorithm">Handle Fetch</a> algorithm makes the <a>potential-navigation-or-subresource request</a> (whose context is either <code>&lt;embed&gt;</code> or <code>&lt;object&gt;</code>) immediately fallback to the network without dispatching <a href="#service-worker-global-scope-fetch-event">fetch</a> event.</li>
        <li>Some of the legacy networking stack code may need to be carefully audited to understand the ramifications of interactions with <a href="#dfn-service-worker">service workers</a>.</li>
      </ul>
    </p>
  </section>

  <section>
    <h3 id="privacy">Privacy</h3>

    <p><a href="#dfn-service-worker">Service workers</a> introduce new persistent storage features including <a href="#dfn-scope-to-registration-map">scope to registration map</a> (for <a href="#dfn-service-worker-registration">service worker registrations</a> and their <a href="#dfn-service-worker">service workers</a>), <a href="#dfn-request-to-response-map">request to response map</a> and <a href="#dfn-name-to-cache-map">name to cache map</a> (for caches), and <a href="#dfn-script-resource-map">script resource map</a> (for script resources). In order to protect users from any potential <a biblio data-biblio-type="informative" lt="unsanctioned-tracking">unsanctioned tracking</a> threat, these persistent storages <em class="rfc2119" title="SHOULD">should</em> be cleared when users intend to clear them and <em class="rfc2119" title="SHOULD">should</em> maintain and interoperate with existing user controls e.g. purging all existing persistent storages.</p>
  </section>
</section>

<section>
  <h2 id="storage-considerations">Storage Considerations</h2>

  <p><a href="#dfn-service-worker">Service workers</a> <em class="rfc2119" title="SHOULD">should</em> take a dependency on <a biblio data-biblio-type="normative" lt="quota-api">Quota Management API</a> that <a href="http://www.w3.org/TR/quota-api/#extensions-to-the-serviceworkerglobalscope-interface">extends the ServiceWorkerGlobalScope</a> with the event listeners {{ServiceWorkerGlobalScope/onbeforeevicted}} and {{ServiceWorkerGlobalScope/onevicted}} to detect a storage pressure and give pre-eviction information to the application.</p>
  <p>The cache write operations in <a href="#dfn-service-worker">service workers</a> when failed due to exceeding the granted quota limit <em class="rfc2119" title="SHOULD">should</em> throw "{{QuotaExceededError}}" exception.</p>
</sections>

<section>
  <h2 id="extensibility">Extensibility</h2>

  <p><a href="#dfn-service-worker">Service workers</a> are extensible from other specifications.</p>

  <section>
    <h3 id="extension-to-service-worker-registration">Define API bound to Service Worker Registration</h3>

    <p>Specifications <em class="rfc2119" title="MAY">may</em> define an API tied to a <a href="#dfn-service-worker-registration">service worker registration</a> by using <a>partial interface</a> definition to the {{ServiceWorkerRegistration}} interface where it <em class="rfc2119" title="MAY">may</em> define the specification specific attributes and methods:</p>

    <pre class="example idl" data-no-idl>
      partial interface ServiceWorkerRegistration {
        // e.g. define an API namespace
        readonly attribute APISpaceType APISpace;
        // e.g. define a method
        Promise&lt;T&gt; methodName(<em>list of arguments</em>);
      };
    </pre>
  </section>

  <section>
    <h3 id="extension-to-extendable-event">Define Functional Event</h3>

    <p>Specifications <em class="rfc2119" title="MAY">may</em> define a <a href="#dfn-functional-events">functional event</a> by extending {{ExtendableEvent}} interface:</p>

    <pre class="example idl" data-no-idl>
      // e.g. define FunctionalEvent interface
      interface FunctionalEvent : ExtendableEvent {
        // add a functional event's own attributes and methods
      };
    </pre>
  </section>

  <section>
    <h3 id="extension-to-service-worker-global-scope">Define Event Handler</h3>

    <p>Specifications <em class="rfc2119" title="MAY">may</em> define an event handler attribute for the corresponding <a href="#dfn-functional-events">functional event</a> using <a>partial interface</a> definition to the {{ServiceWorkerGlobalScope}} interface:</p>

    <pre class="example idl" data-no-idl>
      partial interface ServiceWorkerGlobalScope {
        attribute EventHandler on<em>functionalevent</em>;
      };
    </pre>
  </section>

  <section>
    <h3 id="request-functional-event-dispatch">Request Functional Event Dispatch</h3>

    <p>To request a <a href="#dfn-functional-events">functional event</a> dispatch to a <a href="#dfn-service-worker">service worker</a>, specifications <em class="rfc2119" title="MAY">may</em> invoke <a href="#handle-functional-event-algorithm">Handle Functional Event</a> algorithm with its <a href="#dfn-service-worker-registration">service worker registration</a> <var>registration</var> and the algorithm <var>callbackSteps</var> as the arguments.</p>

    <p>Specifications <em class="rfc2119" title="MAY">may</em> define an algorithm <var>callbackSteps</var> where the corresponding <a href="#dfn-functional-events">functional event</a> can be created and fired with specification specific objects. The algorithm is passed <var>globalObject</var> (a {{ServiceWorkerGlobalScope}} object) at which it <em class="rfc2119" title="MAY">may</em> fire its <a href="#dfn-functional-events">functional events</a>. This algorithm is called on a <a>task</a> <a lt="queue a task">queued</a> by <a href="#handle-functional-event-algorithm">Handle Functional Event</a> algorithm.</p>

    <p class="note">See an <a href="https://notifications.spec.whatwg.org/#activating-a-notification">example</a> hook defined in <a biblio data-biblio-type="informative" lt="notifications">Notifications API</a>.</p>
  </section>
</section>

<section>
  <h2 id="algorithms">Appendix A: Algorithms</h2>

  <p>The following definitions are the user agent's internal data structures used throughout the specification.</p>

  <p>A <dfn id="dfn-scope-to-registration-map">scope to registration map</dfn> is a <a>List</a> of the <a>Record</a> {\[[key]], \[[value]]} where \[[key]] is a string that represents a <a href="#dfn-scope-url">scope url</a> and \[[value]] is a <a href="#dfn-service-worker-registration">service worker registration</a>.</p>

  <P>A <dfn id="dfn-job">job</dfn> is an abstraction of one of register, update, and unregister request for a <a href="#dfn-service-worker-registration">service worker registration</a>.</P>

  <P>A <a href="#dfn-job">job</a> has a <dfn id="dfn-job-type">job type</dfn>, which is one of <em>register</em>, <em>update</em>, and <em>unregister</em>.</P>

  <P>A <a href="#dfn-job">job</a> has a <dfn id="dfn-job-scope-url">scope url</dfn> (a <a for="url">URL</a>).</P>

  <P>A <a href="#dfn-job">job</a> has a <dfn id="dfn-job-script-url">script url</dfn> (a <a for="url">URL</a>).</P>

  <P>A <a href="#dfn-job">job</a> has a <dfn id="dfn-job-worker-type">worker type</dfn> ("<code>classic</code>" or "<code>module</code>").</P>

  <P>A <a href="#dfn-job">job</a> has a <dfn id="dfn-job-client">client</dfn> (a <a href="#dfn-service-worker-client">service worker client</a>). It is initially null.</P>

  <P>A <a>job</a> has a <dfn for=job>referrer</dfn> (a <a for=url>URL</a> or null).</p>

  <P>A <a href="#dfn-job">job</a> has a <dfn id="dfn-job-promise" lt="job promise">promise</dfn> (a <a>promise</a>). It is initially null.</P>

  <P>A <a href="#dfn-job">job</a> has a <dfn id="dfn-job-list-of-equivalent-jobs">list of equivalent jobs</dfn> (a list of <a href="#dfn-job">jobs</a>). It is initially the empty list.</P>

  <P>A <a href="#dfn-job">job</a> has a <dfn id="dfn-job-force-bypass-cache-flag">force bypass cache flag</dfn> It is initially unset.</P>

  <p>Two <a href="#dfn-job">jobs</a> are <dfn id="dfn-job-equivalent">equivalent</dfn> when their <a href="#dfn-job-type">job type</a> is the same and:
    <ul>
      <li>For <em>register</em> and <em>update</em> <a href="#dfn-job">jobs</a>, both their <a href="#dfn-job-scope-url">scope url</a> and the <a href="#dfn-job-script-url">script url</a> are the same.</li>
      <li>For <em>unregister</em> <a href="#dfn-job">jobs</a>, their <a href="#dfn-job-scope-url">scope url</a> is the same.</li>
    </ul>
  </p>

  <p>A <dfn id="dfn-job-queue">job queue</dfn> is a thread safe queue used to synchronize the set of concurrent <a href="#dfn-job">jobs</a>. The <a href="#dfn-job-queue">job queue</a> contains <a href="#dfn-job">jobs</a> as its elements. The <a href="#dfn-job-queue">job queue</a> <em class="rfc2119" title="SHOULD">should</em> satisfy the general properties of FIFO queue. A user agent <em class="rfc2119" title="MUST">must</em> maintain a separate <a href="#dfn-job-queue">job queue</a> for each <a href="#dfn-service-worker-registration">service worker registration</a> keyed by its <a href="#dfn-scope-url">scope url</a>. A <a href="#dfn-job-queue">job queue</a> is initially empty. Unless stated otherwise, the <a href="#dfn-job-queue">job queue</a> referenced from the algorithm steps is a <a href="#dfn-job-queue">job queue</a> for the <a href="#dfn-job">job</a>'s <a href="#dfn-job-scope-url">scope url</a>.</p>

  <section algorithm="create-job-algorithm">
    <h3 id="create-job-algorithm">Create Job</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>jobType</var>, a <a href="#dfn-job-type">job type</a></dd>
        <dd><var>scopeURL</var>, a <a for="url">URL</a></dd>
        <dd><var>scriptURL</var>, a <a for="url">URL</a></dd>
        <dd><var>promise</var>, a <a>promise</a></dd>
        <dd><var>client</var>, a <a href="#dfn-service-worker-client">service worker client</a></dd>
      <dt>Output</dt>
        <dd><var>job</var>, a <a href="#dfn-job">job</a></dd>
    </dl>
    <ol>
      <li>Let <var>job</var> be a new <a href="#dfn-job">job</a>.</li>
      <li>Set <var>job</var>'s <a href="#dfn-job-type">job type</a> to <var>jobType</var>.</li>
      <li>Set <var>job</var>'s <a href="#dfn-job-scope-url">scope url</a> to <var>scopeURL</var>.</li>
      <li>Set <var>job</var>'s <a href="#dfn-job-script-url">script url</a> to <var>scriptURL</var>.</li>
      <li>Set <var>job</var>'s <a href="#dfn-job-promise">promise</a> to <var>promise</var>.</li>
      <li>Set <var>job</var>'s <a href="#dfn-job-client">client</a> to <var>client</var>.</li>
      <li>If <var>client</var> is not null, set <var>job</var>'s <a>referrer</a> to <var>client</var>'s <a>creation URL</a>.</li>
      <li>Return <var>job</var>.</li>
    </ol>
  </section>

  <section algorithm="schedule-job-algorithm">
    <h3 id="schedule-job-algorithm">Schedule Job</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>job</var>, a <a href="#dfn-job">job</a></dd>
      <dt>Output</dt>
        <dd>none</dd>
    </dl>
    <ol>
      <li>If the <a href="#dfn-job-queue">job queue</a> is empty, then:
        <ol>
          <li>Push <var>job</var> to the <a href="#dfn-job-queue">job queue</a> and invoke <a href="#run-job-algorithm">Run Job</a>.</li>
        </ol>
      </li>
      <li>Else:
        <ol>
          <li>Let <var>lastJob</var> be the element at the back of the <a href="#dfn-job-queue">job queue</a>.</li>
          <li>If <var>job</var> is <a href="#dfn-job-equivalent">equivalent</a> to <var>lastJob</var> and <var>lastJob</var>'s <a href="#dfn-job-promise">promise</a> has not settled, append <var>job</var> to <var>lastJob</var>'s <a href="#dfn-job-list-of-equivalent-jobs">list of equivalent jobs</a>.</li>
          <li>Else, push <var>job</var> to the <a href="#dfn-job-queue">job queue</a>.</li>
        </ol>
      </li>
    </ol>
  </section>

  <section algorithm="run-job-algorithm">
    <h3 id="run-job-algorithm">Run Job</h3>

    <dl>
      <dt>Input</dt>
        <dd>none</dd>
      <dt>Output</dt>
        <dd>none</dd>
    </dl>
    <ol>
      <li><a>Assert</a>: the <a href="#dfn-job-queue">job queue</a> is not empty.</li>
      <li><a>Queue a task</a> to run these steps:
        <ol>
          <li>Let <var>job</var> be the element in the front of the <a href="#dfn-job-queue">job queue</a>.</li>
          <li>If <var>job</var>'s <a href="#dfn-job-type">job type</a> is <em>register</em>, run <a href="#register-algorithm">Register</a> with <var>job</var> <a>in parallel</a>.</li>
          <li>Else if <var>job</var>'s <a href="#dfn-job-type">job type</a> is <em>update</em>, run <a href="#update-algorithm">Update</a> with <var>job</var> <a>in parallel</a>.
            <p class="note">For a register job and an update job, the user agent delays queuing a task for running the job until after the document initiated the job has been dispatched {{Document/DOMContentLoaded}} event.</p>
          </li>
          <li>Else if <var>job</var>'s <a href="#dfn-job-type">job type</a> is <em>unregister</em>, run <a href="#unregister-algorithm">Unregister</a> with <var>job</var> <a>in parallel</a>.</li>
        </ol>
      </li>
    </ol>
  </section>

  <section algorithm="finish-job-algorithm">
    <h3 id="finish-job-algorithm">Finish Job</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>job</var>, a <a href="#dfn-job">job</a></dd>
      <dt>Output</dt>
        <dd>none</dd>
    </dl>
    <ol>
      <li><a>Assert</a>: the top element in the <a href="#dfn-job-queue">job queue</a> is <var>job</var>.</li>
      <li>Pop the top element from the <a href="#dfn-job-queue">job queue</a>.</li>
      <li>If the <a href="#dfn-job-queue">job queue</a> is not empty, invoke <a href="#run-job-algorithm">Run Job</a> with the top element of the <a href="#dfn-job-queue">job queue</a>.</li>
    </ol>
  </section>

  <section algorithm="resolve-job-promise-algorithm">
    <h3 id="resolve-job-promise-algorithm">Resolve Job Promise</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>job</var>, a <a href="#dfn-job">job</a></dd>
        <dd><var>value</var>, any</dd>
      <dt>Output</dt>
        <dd>none</dd>
    </dl>
    <ol>
      <li>If <var>job</var>'s <a href="#dfn-job-client">client</a> is not null, <a>queue a task</a> to resolve <var>job</var>'s <a href="#dfn-job-promise">promise</a> with <var>value</var> on <var>job</var>'s <a href="#dfn-job-client">client</a>'s <a>responsible event loop</a> using the <a>DOM manipulation task source</a> as the <a>task source</a>.</li>
      <li>For each <var>equivalentJob</var> in <var>job</var>'s <a href="#dfn-job-list-of-equivalent-jobs">list of equivalent jobs</a>:
        <ol>
          <li>If <var>equivalentJob</var>'s <a href="#dfn-job-client">client</a> is not null, <a>queue a task</a> to resolve <var>equivalentJob</var>'s <a href="#dfn-job-promise">promise</a> with <var>value</var> on <var>equivalentJob</var>'s <a href="#dfn-job-client">client</a>'s <a>responsible event loop</a> using the <a>DOM manipulation task source</a> as the <a>task source</a>.</li>
        </ol>
      </li>
    </ol>
  </section>

  <section algorithm="reject-job-promise-algorithm">
    <h3 id="reject-job-promise-algorithm">Reject Job Promise</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>job</var>, a <a href="#dfn-job">job</a></dd>
        <dd><var>reason</var>, an <a>exception</a></dd>
      <dt>Output</dt>
        <dd>none</dd>
    </dl>
    <ol>
      <li>If <var>job</var>'s <a href="#dfn-job-client">client</a> is not null, <a>queue a task</a> to reject <var>job</var>'s <a href="#dfn-job-promise">promise</a> with <var>reason</var> on <var>job</var>'s <a href="#dfn-job-client">client</a>'s <a>responsible event loop</a> using the <a>DOM manipulation task source</a> as the <a>task source</a>.</li>
      <li>For each <var>equivalentJob</var> in <var>job</var>'s <a href="#dfn-job-list-of-equivalent-jobs">list of equivalent jobs</a>:
        <ol>
          <li>If <var>equivalentJob</var>'s <a href="#dfn-job-client">client</a> is not null, <a>queue a task</a> to reject <var>equivalentJob</var>'s <a href="#dfn-job-promise">promise</a> with <var>reason</var> on <var>equivalentJob</var>'s <a href="#dfn-job-client">client</a>'s <a>responsible event loop</a> using the <a>DOM manipulation task source</a> as the <a>task source</a>.</li>
        </ol>
      </li>
    </ol>
  </section>

  <section algorithm="start-register-algorithm">
    <h3 id="start-register-algorithm">Start Register</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>scopeURLString</var>, a string</dd>
        <dd><var>scriptURL</var>, a <a for="url">URL</a></dd>
        <dd><var>promise</var>, a <a>promise</a></dd>
        <dd><var>client</var>, a <a href="#dfn-service-worker-client">service worker client</a></dd>
        <dd><var>referrer</var>, a <a for=url>URL</a></dd>
        <dd><var>workerType</var>, a <a>worker type</a></dd>
      <dt>Output</dt>
        <dd>none</dd>
    </dl>
    <ol>
      <li>If <var>scriptURL</var> is failure, reject <var>promise</var> with a <code>TypeError</code> and abort these steps.</li>
      <li>If <var>scriptURL</var>'s <a for="url">scheme</a> is not one of "<code>http</code>" and "<code>https</code>", reject <var>promise</var> with a <code>TypeError</code> and abort these steps.</li>
      <li>If any of the strings in <var>scriptURL</var>'s <a for="url">path</a> contains either <a>ASCII case-insensitive</a> "<code>%2f</code>" or <a>ASCII case-insensitive</a> "<code>%5c</code>", reject <var>promise</var> with a <code>TypeError</code> and abort these steps.</li>
      <li>Let <var>scopeURL</var> be null.</li>
      <li>If <var>scopeURLString</var> is null, set <var>scopeURL</var> to the result of <a for="url">parsing</a> a string "<code>./</code>" with <var>scriptURL</var>.
        <p class="note">The scope url for the registration is set to the location of the service worker script by default.</p>
      </li>
      <li>Else, set <var>scopeURL</var> to the result of <a for="url">parsing</a> <var>scopeURLString</var> with <a>entry settings object</a>'s <a>API base URL</a>.</li>
      <li>If <var>scopeURL</var> is failure, reject <var>promise</var> with a <code>TypeError</code> and abort these steps.</li>
      <li>If <var>scopeURL</var>'s <a for="url">scheme</a> is not one of "<code>http</code>" and "<code>https</code>", reject <var>promise</var> with a <code>TypeError</code> and abort these steps.</li>
      <li>If any of the strings in <var>scopeURL</var>'s <a for="url">path</a> contains either <a>ASCII case-insensitive</a> "<code>%2f</code>" or <a>ASCII case-insensitive</a> "<code>%5c</code>", reject <var>promise</var> with a <code>TypeError</code> and abort these steps.</li>
      <li>Let <var>job</var> be the result of running [[#create-job-algorithm]] with <em>register</em>, <var>scopeURL</var>, <var>scriptURL</var>, <var>promise</var>, and <var>client</var>.</li>
      <li>Set <var>job</var>'s <a>worker type</a> to <var>workerType</var>.</li>
      <li>Set <var>job</var>'s <a>referrer</a> to <var>referrer</var>.</li>
      <li>Invoke [[#schedule-job-algorithm]] with <var>job</var>.</li>
    </ol>
  </section>

  <section algorithm="register-algorithm">
    <h3 id="register-algorithm">Register</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>job</var>, a <a href="#dfn-job">job</a></dd>
      <dt>Output</dt>
        <dd><var>promise</var>, a <a>promise</a></dd>
    </dl>
    <ol>
      <li>If the result of running <a>Is origin potentially trustworthy</a> with the <a for="resource">origin</a> of <var>job</var>'s <a href="#dfn-job-script-url">script url</a> as the argument is <code>Not Trusted</code>, then:
        <ol>
          <li>Invoke <a href="#reject-job-promise-algorithm">Reject Job Promise</a> with <var>job</var> and a "{{SecurityError}}" exception.</li>
          <li>Invoke <a href="#finish-job-algorithm">Finish Job</a> with <var>job</var> and abort these steps.</li>
        </ol>
      </li>
      <li>If the <a for="resource">origin</a> of <var>job</var>'s <a href="#dfn-job-script-url">script url</a> is not <var>job</var>'s <a for=job>referrer</a>'s <a for="resource">origin</a>, then:
        <ol>
          <li>Invoke <a href="#reject-job-promise-algorithm">Reject Job Promise</a> with <var>job</var> and a "{{SecurityError}}" exception.</li>
          <li>Invoke <a href="#finish-job-algorithm">Finish Job</a> with <var>job</var> and abort these steps.</li>
        </ol>
      </li>
      <li>If the <a for="resource">origin</a> of <var>job</var>'s <a href="#dfn-job-scope-url">scope url</a> is not <var>job</var>'s <a for=job>referrer</a>'s <a for="resource">origin</a>, then:
        <ol>
          <li>Invoke <a href="#reject-job-promise-algorithm">Reject Job Promise</a> with <var>job</var> and a "{{SecurityError}}" exception.</li>
          <li>Invoke <a href="#finish-job-algorithm">Finish Job</a> with <var>job</var> and abort these steps.</li>
        </ol>
      </li>
      <li>Let <var>registration</var> be the result of running the <a href="#get-registration-algorithm">Get Registration</a> algorithm passing <var>job</var>'s <a href="#dfn-job-scope-url">scope url</a> as the argument.</li>
      <li>If <var>registration</var> is not null, then:
        <ol>
          <li>If <var>registration</var>'s <a href="#dfn-uninstalling-flag">uninstalling flag</a> is set, unset it.</li>
          <li>Let <var>newestWorker</var> be the result of running the <a href="#get-newest-worker-algorithm">Get Newest Worker</a> algorithm passing <var>registration</var> as the argument.</li>
          <li>If <var>newestWorker</var> is not null and <var>job</var>'s <a href="#dfn-job-script-url">script url</a> <a for="url">equals</a> <var>newestWorker</var>'s <a href="#dfn-script-url">script url</a> with the <em>exclude fragments flag</em> set, then:
            <ol>
              <li>Invoke <a href="#resolve-job-promise-algorithm">Resolve Job Promise</a> with <var>job</var> and the {{ServiceWorkerRegistration}} object which represents <var>registration</var>.</li>
              <li>Invoke <a href="#finish-job-algorithm">Finish Job</a> with <var>job</var> and abort these steps.</li>
            </ol>
          </li>
        </ol>
      </li>
      <li>Else:
        <ol>
          <li>Invoke <a href="#set-registration-algorithm">Set Registration</a> algorithm passing <var>job</var>'s <a href="#dfn-job-scope-url">scope url</a> as its argument.</li>
        </ol>
      </li>
      <li>Invoke <a href="#update-algorithm">Update</a> algorithm passing <var>job</var> as the argument.</li>
    </ol>
  </section>

  <section algorithm="update-algorithm">
    <h3 id="update-algorithm">Update</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>job</var>, a <a href="#dfn-job">job</a></dd>
      <dt>Output</dt>
        <dd>none</dd>
    </dl>
    <ol>
      <li>Let <var>registration</var> be the result of running the <a href="#get-registration-algorithm">Get Registration</a> algorithm passing <var>job</var>'s <a href="#dfn-job-scope-url">scope url</a> as the argument.</li>
      <li>If <var>registration</var> is null or <var>registration</var>'s <a href="#dfn-uninstalling-flag">uninstalling flag</a> is set, then:
        <ol>
          <li>Invoke <a href="#reject-job-promise-algorithm">Reject Job Promise</a> with <var>job</var> and a <code>TypeError</code>.</li>
          <li>Invoke <a href="#finish-job-algorithm">Finish Job</a> with <var>job</var> and abort these steps.</li>
        </ol>
      </li>
      <li>Let <var>newestWorker</var> be the result of running <a href="#get-newest-worker-algorithm">Get Newest Worker</a> algorithm passing <var>registration</var> as the argument.</li>
      <li>If <var>job</var>'s <a href="#dfn-job-type">job type</a> is <em>update</em>, and <var>newestWorker</var>'s <a href="#dfn-script-url">script url</a> does not <a for="url">equal</a> <var>job</var>'s <a href="#dfn-job-script-url">script url</a> with the <em>exclude fragments flag</em> set, then:
        <ol>
          <li>Invoke <a href="#reject-job-promise-algorithm">Reject Job Promise</a> with <var>job</var> and a <code>TypeError</code>.</li>
          <li>Invoke <a href="#finish-job-algorithm">Finish Job</a> with <var>job</var> and abort these steps.</li>
        </ol>
      </li>
      <li>Switching on <var>job</var>'s <a>worker type</a>, run these substeps with the following options:
        <dl>
        <dt><em>"<code>classic</code>"</em></dt>
        <dd><p><a>Fetch a classic worker script</a> given <var>job</var>’s <a>serialized</a> <a href="#dfn-job-script-url">script url</a>, <var>job</var>’s <a href="#dfn-job-client">client</a>, and "<code>serviceworker</code>".</p></dd>
        <dt><em>"<code>module</code>"</em></dt>
        <dd><p><a>Fetch a module worker script tree</a> given <var>job</var>’s <a>serialized</a> <a href="#dfn-job-script-url">script url</a>, <var>job</var>’s <a href="#dfn-job-client">client</a>, "<code>serviceworker</code>", "<code>omit</code>", and the to-be-created <a>environment settings object</a> for this service worker.</p></dd> <!-- TODO: reorganize algorithm so that the worker environment is created before fetching happens -->
        </dl>
        <p>To <a for="fetching scripts">perform the fetch</a> given <var>request</var>, run the following steps if the <a for="fetching scripts">is top-level</a> flag is set:</p>
        <ol>
          <li>Append `<code>Service-Worker</code>`/`<code>script</code>` to <var>request</var>'s <a for="request">header list</a>.
            <p class="note">See the definition of the Service-Worker header in Appendix B: Extended HTTP headers.</p>
          </li>
          <li>Set <var>request</var>'s <a>skip service worker flag</a> and <var>request</var>'s <a>redirect mode</a> to "<code>error</code>".</li>
          <li>If <var>newestWorker</var> is not null and <var>registration</var>'s <a href="#dfn-last-update-check-time">last update check time</a> is not null, then:
            <ol>
              <li>If the time difference in seconds calculated by the current time minus <var>registration</var>'s <a href="#dfn-last-update-check-time">last update check time</a> is greater than 86400, or <em>force bypass cache flag</em> is set, set <var>request</var>'s <a>cache mode</a> to "<code>reload</code>".</li>
            </ol>
            <p class="note">Even if the cache mode is not set to "reload", the user agent obeys Cache-Control header's max-age value in the network layer to determine if it should bypass the browser cache.</p>
          </li>
          <li><a>Fetch</a> <var>request</var>, and asynchronously wait to run the remaining steps as part of fetch's <a>process response</a> for the <a for="fetch">response</a> <var>response</var>.</li>
          <li><a>Extract a MIME type</a> from the <var>response</var>'s <a for="response">header list</a>. If this MIME type (ignoring parameters) is not one of <code>text/javascript</code>, <code>application/x-javascript</code>, and <code>application/javascript</code>, then:
            <ol>
              <li>Invoke <a href="#reject-job-promise-algorithm">Reject Job Promise</a> with <var>job</var> and a "{{SecurityError}}" exception.</li>
              <li>Asynchronously complete these steps with a <a>network error</a>.</li>
            </ol>
          </li>
          <li>Let <var>serviceWorkerAllowed</var> be the result of <a for="header">parsing</a> `<code>Service-Worker-Allowed</code>` in <var>response</var>'s <a for="response">header list</a>.
            <p class="note">See the definition of the Service-Worker-Allowed header in Appendix B: Extended HTTP headers.</p>
          </li>
          <li>If <var>serviceWorkerAllowed</var> is failure, then:
            <ol>
              <li>Asynchronously complete these steps with a <a>network error</a>.</li>
            </ol>
          </li>
          <li>Let <var>scopeURL</var> be <var>registration</var>'s <a href="#dfn-scope-url">scope url</a>.</li>
          <li>Let <var>maxScopeString</var> be null.</li>
          <li>If <var>serviceWorkerAllowed</var> is null, then:
            <ol>
              <li>Set <var>maxScopeString</var> to "<code>/</code>" concatenated with the strings, except the last string that denotes the script's file name, in <var>job</var>'s <a href="#dfn-job-script-url">script url</a>'s <a for="url">path</a> (including empty strings), separated from each other by "<code>/</code>".</li>
            </ol>
          </li>
          <li>Else:
            <ol>
              <li>Let <var>maxScope</var> be the result of <a for="url">parsing</a> <var>serviceWorkerAllowed</var> with <var>job</var>'s <a href="#dfn-job-script-url">script url</a>.</li>
              <li>Set <var>maxScopeString</var> to "<code>/</code>" concatenated with the strings in <var>maxScope</var>'s <a for="url">path</a> (including empty strings), separated from each other by "<code>/</code>".</li>
            </ol>
          </li>
          <li>Let <var>scopeString</var> be "<code>/</code>" concatenated with the strings in <var>scopeURL</var>'s <a for="url">path</a> (including empty strings), separated from each other by "<code>/</code>".</li>
          <li>If <var>scopeString</var> starts with <var>maxScopeString</var>, do nothing.</li>
          <li>Else:
            <ol>
              <li>Invoke <a href="#reject-job-promise-algorithm">Reject Job Promise</a> with <var>job</var> and a "{{SecurityError}}" exception.</li>
              <li>Asynchronously complete these steps with a <a>network error</a>.</li>
            </ol>
          </li>
          <li>If <var>response</var>'s <a for="response" href="https://github.com/whatwg/fetch/issues/376">cache state</a> is not "<code>local</code>", set <var>registration</var>'s <a href="#dfn-last-update-check-time">last update check time</a> to the current time.
            <p class="issue">The response's cache state concept had been removed from fetch. The fetch issue <a href="https://github.com/whatwg/fetch/issues/376">#376</a> tracks the request to restore the concept or add some similar way to check this state.</p>
          </li>
          <li>Return true.</li>
        </ol>
        <p>If the algorithm asynchronously completes with null, then:
          <ol>
            <li>
                <p>Invoke <a href="#reject-job-promise-algorithm">Reject Job Promise</a> with <var>job</var> and a <code>TypeError</code>.</p>

                <p class="note">This will do nothing if <a href="#reject-job-promise-algorithm">Reject Job Promise</a> was previously invoked with a "{{SecurityError}}" exception.</p>
            </li>
            <li>If <var>newestWorker</var> is null, invoke <a href="#clear-registration-algorithm">Clear Registration</a> algorithm passing <var>registration</var> as its argument.</li>
            <li>Invoke <a href="#finish-job-algorithm">Finish Job</a> with <var>job</var> and abort these steps.</li>
          </ol>
        </p>
        <p>Else, continue the rest of these steps after the algorithm's asynchronous completion, with <var>script</var> being the asynchronous completion value.</p>
      </li>
      <li>If <var>newestWorker</var> is not null, <var>newestWorker</var>'s <a href="#dfn-script-url">script url</a> <a for="url">equals</a> <var>job</var>'s <a href="#dfn-job-script-url">script url</a> with the <em>exclude fragments flag</em> set, and <var>script</var> is a byte-for-byte match with <var>newestWorker</var>'s <a href="#dfn-script-resource">script resource</a>, then:
        <ol>
          <li>Invoke <a href="#resolve-job-promise-algorithm">Resolve Job Promise</a> with <var>job</var> and the {{ServiceWorkerRegistration}} object which represents <var>registration</var>.</li>
          <li>Invoke <a href="#finish-job-algorithm">Finish Job</a> with <var>job</var> and abort these steps.</li>
        </ol>
      </li>
      <li>Else:
        <ol>
          <li>Let <var>worker</var> be a new <a href="#dfn-service-worker">service worker</a>.</li>
          <li>Generate a unique opaque string and set <var>worker</var>'s <a href="#dfn-service-worker-id">id</a> to the value.</li>
          <li>Set <var>worker</var>'s <a href="#dfn-script-url">script url</a> to <var>job</var>'s <a href="#dfn-job-script-url">script url</a>, <var>worker</var>'s <a href="#dfn-script-resource">script resource</a> to <var>script</var>, and <var>worker</var>'s <a href="#dfn-type">type</a> to <var>job</var>'s <a>worker type</a>.</li>
          <li>Invoke <a href="#run-service-worker-algorithm">Run Service Worker</a> algorithm with <var>worker</var> as the argument.</li>
          <li>If an uncaught runtime script error occurs during the above step, then:
            <ol>
              <li>Invoke <a href="#reject-job-promise-algorithm">Reject Job Promise</a> with <var>job</var> and a <code>TypeError</code>.</li>
              <li>If <var>newestWorker</var> is null, invoke <a href="#clear-registration-algorithm">Clear Registration</a> algorithm passing <var>registration</var> as its argument.</li>
              <li>Invoke <a href="#finish-job-algorithm">Finish Job</a> with <var>job</var> and abort these steps.</li>
            </ol>
          </li>
        </ol>
      </li>
      <li>Invoke <a href="#installation-algorithm">Install</a> algorithm with <var>job</var>, <var>worker</var>, and <var>registration</var> as its arguments.</li>
    </ol>
  </section>

  <section algorithm="soft-update-algorithm">
    <h3 id="soft-update-algorithm">Soft Update</h3>

    <p>The user agent <em class="rfc2119" title="MAY">may</em> call this as often as it likes to check for updates.</p>

    <dl>
      <dt>Input</dt>
        <dd><var>registration</var>, a <a href="#dfn-service-worker-registration">service worker registration</a></dd>
        <dd><em>force bypass cache flag</em>, an optional flag unset by default</dd>
        <p class="note">Implementers may use the <em>force bypass cache flag</em> to aid debugging (e.g. invocations from developer tools), and other specifications that extend service workers may also use the flag on their own needs.</p>
      <dt>Output</dt>
        <dd>None</dd>
    </dl>
    <ol>
      <li>Let <var>newestWorker</var> be the result of running <a href="#get-newest-worker-algorithm">Get Newest Worker</a> algorithm passing <var>registration</var> as its argument.</li>
      <li>If <var>newestWorker</var> is null, abort these steps.</li>
      <li>Let <var>job</var> be the result of running <a href="#create-job-algorithm">Create Job</a> with <em>update</em>, <var>registration</var>'s <a href="#dfn-scope-url">scope url</a>, <var>newestWorker</var>'s <a href="#dfn-script-url">script url</a>, null, and null.</li>
      <li>Set <var>job</var>'s <a>worker type</a> to <var>newestWorker</var>'s <a for="service worker">type</a>.</li>
      <li>Set <var>job</var>'s <a href="#dfn-job-force-bypass-cache-flag">force bypass cache flag</a> if its <em>force bypass cache flag</em> is set.</li>
      <li>Invoke <a href="#schedule-job-algorithm">Schedule Job</a> with <var>job</var>.</li>
    </ol>
  </section>

  <section algorithm="installation-algorithm">
    <h3 id="installation-algorithm">Install</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>job</var>, a <a href="#dfn-job">job</a></dd>
        <dd><var>worker</var>, a <a href="#dfn-service-worker">service worker</a></dd>
        <dd><var>registration</var>, a <a href="#dfn-service-worker-registration">service worker registration</a></dd>
      <dt>Output</dt>
        <dd>none</dd>
    </dl>
    <ol>
      <li>Let <var>installFailed</var> be false.</li>
      <li>Let <var>newestWorker</var> be the result of running <a href="#get-newest-worker-algorithm">Get Newest Worker</a> algorithm passing <var>registration</var> as its argument.</li>
      <li>Let <var>redundantWorker</var> be null.</li>
      <li>Run the <a href="#update-registration-state-algorithm">Update Registration State</a> algorithm passing <var>registration</var>, "<code>installing</code>" and <var>worker</var> as the arguments.</li>
      <li>Run the <a href="#update-state-algorithm">Update Worker State</a> algorithm passing <var>registration</var>'s <a href="#dfn-installing-worker">installing worker</a> and <em>installing</em> as the arguments.</li>
      <li><a>Assert</a>: <var>job</var>'s <a href="#dfn-job-promise">promise</a> is not null.</li>
      <li>Invoke <a href="#resolve-job-promise-algorithm">Resolve Job Promise</a> with <var>job</var> and the {{ServiceWorkerRegistration}} object which represents <var>registration</var>.</li>
      <li><a>Queue a task</a> to <a>fire a simple event</a> named <code>updatefound</code> at all the {{ServiceWorkerRegistration}} objects for all the <a href="#dfn-service-worker-client">service worker clients</a> whose <a>creation url</a> <a href="#scope-match-algorithm">matches</a> <var>registration</var>'s <a href="#dfn-scope-url">scope url</a> and all the <a href="#dfn-service-worker">service workers</a> whose <a href="#dfn-containing-service-worker-registration">containing service worker registration</a> is <var>registration</var>.</li>
      <li>Let <var>installingWorker</var> be <var>registration</var>'s <a href="#dfn-installing-worker">installing worker</a>.</li>
      <li>Invoke <a href="#run-service-worker-algorithm">Run Service Worker</a> algorithm with <var>installingWorker</var> as the argument.</li>
      <li><a>Queue a task</a> <var>task</var> to run the following substeps:
        <ol>
          <li>Create a <a>trusted event</a> <var>e</var> that uses the {{InstallEvent}} interface, with the event type <code><a href="#service-worker-global-scope-install-event">install</a></code>, which does not bubble and is not cancelable.</li>
          <li><a>Dispatch</a> <var>e</var> at <var>installingWorker</var>'s <a>environment settings object</a>'s <a>global object</a> <var>globalObject</var>.</li>
          <li><em>WaitForAsynchronousExtensions</em>: Run the following substeps <a>in parallel</a>:
            <ol>
              <li>Wait until <var>e</var>'s <a>extensions allowed flag</a> is unset.</li>
              <li>If the result of <a>waiting for all</a> of <var>e</var>'s <a>extend lifetime promises</a> rejected, set <var>installFailed</var> to true.</li>
            </ol>
          </li>
        </ol>
      </li>
      <p>If <var>task</var> is discarded or the script has been aborted by the <a href="#terminate-service-worker-algorithm">termination</a> of <var>installingWorker</var>, set <var>installFailed</var> to true.</p>
      <li>Wait for <var>task</var> to have executed or been discarded.</li>
      <li>Wait for the step labeled <em>WaitForAsynchronousExtensions</em> to complete.</li>
      <li>If <var>installFailed</var> is true, then:
        <ol>
          <li>Set <var>redundantWorker</var> to <var>registration</var>'s <a href="#dfn-installing-worker">installing worker</a>.</li>
          <li>Run the <a href="#update-registration-state-algorithm">Update Registration State</a> algorithm passing <var>registration</var>, "<code>installing</code>" and null as the arguments.</li>
          <li>Run the <a href="#update-state-algorithm">Update Worker State</a> algorithm passing <var>redundantWorker</var> and <em>redundant</em> as the arguments.</li>
          <li>If <var>newestWorker</var> is null, invoke <a href="#clear-registration-algorithm">Clear Registration</a> algorithm passing <var>registration</var> as its argument.</li>
          <li>Invoke <a href="#finish-job-algorithm">Finish Job</a> with <var>job</var> and abort these steps.</li>
        </ol>
      </li>
      <li>Set <var>registration</var>'s <a href="#dfn-installing-worker">installing worker</a>'s <a href="#dfn-imported-scripts-updated-flag">imported scripts updated flag</a>.</li>
      <li>If <var>registration</var>'s <a href="#dfn-waiting-worker">waiting worker</a> is not null, then:
        <ol>
          <li>Set <var>redundantWorker</var> to <var>registration</var>'s <a href="#dfn-waiting-worker">waiting worker</a>.</li>
          <li><a href="#terminate-service-worker-algorithm">Terminate</a> <var>redundantWorker</var>.</li>
          <li>The user agent <em class="rfc2119" title="MAY">may</em> abort in-flight requests triggered by <var>redundantWorker</var>.</li>
        </ol>
      </li>
      <li>Run the <a href="#update-registration-state-algorithm">Update Registration State</a> algorithm passing <var>registration</var>, "<code>waiting</code>" and <var>registration</var>'s <a href="#dfn-installing-worker">installing worker</a> as the arguments.</li>
      <li>Run the <a href="#update-registration-state-algorithm">Update Registration State</a> algorithm passing <var>registration</var>, "<code>installing</code>" and null as the arguments.</li>
      <li>Run the <a href="#update-state-algorithm">Update Worker State</a> algorithm passing <var>registration</var>'s <a href="#dfn-waiting-worker">waiting worker</a> and <em>installed</em> as the arguments.</li>
      <li>If <var>redundantWorker</var> is not null, run the <a href="#update-state-algorithm">Update Worker State</a> algorithm passing <var>redundantWorker</var> and <em>redundant</em> as the arguments.</li>
      <li>If <var>registration</var>'s <a href="#dfn-waiting-worker">waiting worker</a>'s <a href="#dfn-skip-waiting-flag">skip waiting flag</a> is set, then:
        <ol>
          <li>Run <a href="#activation-algorithm">Activate</a> algorithm passing <var>registration</var> as the argument.</li>
          <li>Invoke <a href="#finish-job-algorithm">Finish Job</a> with <var>job</var> and abort these steps.</li>
        </ol>
      </li>
      <li>Invoke <a href="#finish-job-algorithm">Finish Job</a> with <var>job</var>.</li>
      <li>Wait for all the <a>tasks</a> <a lt="queue a task">queued</a> by <a href="#update-state-algorithm">Update Worker State</a> invoked in this algorithm have executed.</li>
      <li>Wait until no <a href="#dfn-service-worker-client">service worker client</a> is <a href="#dfn-use">using</a> <var>registration</var> or <var>registration</var>'s <a href="#dfn-waiting-worker">waiting worker</a>'s <a href="#dfn-skip-waiting-flag">skip waiting flag</a> is set.</li>
      <li>If <var>registration</var>'s <a href="#dfn-waiting-worker">waiting worker</a> <var>waitingWorker</var> is not null and <var>waitingWorker</var>'s <a href="#dfn-skip-waiting-flag">skip waiting flag</a> is not set, invoke <a href="#activation-algorithm">Activate</a> algorithm with <var>registration</var> as its argument.</li>
    </ol>
  </section>

  <section algorithm="activation-algorithm">
    <h3 id="activation-algorithm">Activate</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>registration</var>, a <a href="#dfn-service-worker-registration">service worker registration</a></dd>
      <dt>Output</dt>
        <dd>None</dd>
    </dl>
    <ol>
      <li>If <var>registration</var>'s <a href="#dfn-waiting-worker">waiting worker</a> is null, abort these steps.</li>
      <li>Let <var>redundantWorker</var> be null.</li>
      <li>If <var>registration</var>'s <a href="#dfn-active-worker">active worker</a> is not null, then:
        <ol>
          <li>Set <var>redundantWorker</var> to <var>registration</var>'s <a href="#dfn-active-worker">active worker</a>.</li>
          <li>Wait for <var>redundantWorker</var> to finish handling any in-progress requests.
          </li>
          <li><a href="#terminate-service-worker-algorithm">Terminate</a> <var>redundantWorker</var>.</li>
        </ol>
      </li>
      <li>Run the <a href="#update-registration-state-algorithm">Update Registration State</a> algorithm passing <var>registration</var>, "<code>active</code>" and <var>registration</var>'s <a href="#dfn-waiting-worker">waiting worker</a> as the arguments.</li>
      <li>Run the <a href="#update-registration-state-algorithm">Update Registration State</a> algorithm passing <var>registration</var>, "<code>waiting</code>" and null as the arguments.</li>
      <li>Run the <a href="#update-state-algorithm">Update Worker State</a> algorithm passing <var>registration</var>'s <a href="#dfn-active-worker">active worker</a> and <em>activating</em> as the arguments.
        <p class="note">Once an active worker is activating, neither a runtime script error nor a force termination of the active worker prevents the active worker from getting activated.</p>
      </li>
      <li>If <var>redundantWorker</var> is not null, run the <a href="#update-state-algorithm">Update Worker State</a> algorithm passing <var>redundantWorker</var> and <em>redundant</em> as the arguments.</li>
      <li>For each <a href="#dfn-service-worker-client">service worker client</a> <var>client</var> whose <a>creation url</a> <a href="#scope-match-algorithm">matches</a> <var>registration</var>'s <a href="#dfn-scope-url">scope url</a>:
        <ol>
          <li>If <var>client</var> is a <a href="#dfn-window-client">window client</a>, unassociate <var>client</var>'s <a>responsible document</a> from its <a>application cache</a>, if it has one.</li>
          <li>Else if <var>client</var> is a <a href="#dfn-sharedworker-client">shared worker client</a>, unassociate <var>client</var>'s <a>global object</a> from its <a>application cache</a>, if it has one.</li>
        </ol>
        <p class="note">Resources will now use the service worker registration instead of the existing application cache.</p>
      </li>
      <li>For each <a href="#dfn-service-worker-client">service worker client</a> <var>client</var> who is <a href="#dfn-use">using</a> <var>registration</var>:
        <ol>
          <li>Set <var>client</var>'s <a href="#dfn-active-worker">active worker</a> to <var>registration</var>'s <a href="#dfn-active-worker">active worker</a>.</li>
          <li>Invoke <a href="#notify-controller-change-algorithm">Notify Controller Change</a> algorithm with <var>client</var> as the argument.</li>
        </ol>
      </li>
      <li>Let <var>activeWorker</var> be <var>registration</var>'s <a href="#dfn-active-worker">active worker</a>.</li>
      <li>Invoke <a href="#run-service-worker-algorithm">Run Service Worker</a> algorithm with <var>activeWorker</var> as the argument.</li>
      <li><a>Queue a task</a> <var>task</var> to run the following substeps:
        <ol>
          <li>Create a <a>trusted event</a> <var>e</var> that uses the {{ExtendableEvent}} interface, with the event type <code><a href="#service-worker-global-scope-activate-event">activate</a></code>, which does not bubble and is not cancelable.</li>
          <li><a>Dispatch</a> <var>e</var> at <var>activeWorker</var>'s <a>environment settings object</a>'s <a>global object</a>.</li>
          <li><em>WaitForAsynchronousExtensions</em>: Wait, <a>in parallel</a>, until <var>e</var>'s <a>extensions allowed flag</a> is unset.</li>
        </ol>
      </li>
      <li>Wait for <var>task</var> to have executed or been discarded, or the script to have been aborted by the <a href="#terminate-service-worker-algorithm">termination</a> of <var>activeWorker</var>.</li>
      <li>Wait for the step labeled <em>WaitForAsynchronousExtensions</em> to complete.</li>
      <li>Run the <a href="#update-state-algorithm">Update Worker State</a> algorithm passing <var>registration</var>'s <a href="#dfn-active-worker">active worker</a> and <em>activated</em> as the arguments.</li>
    </ol>
  </section>

  <section algorithm="run-service-worker-algorithm">
    <h3 id="run-service-worker-algorithm">Run Service Worker</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>serviceWorker</var>, a <a href="#dfn-service-worker">service worker</a></dd>
      <dt>Output</dt>
        <dd>None</dd>
    </dl>
    <ol>
      <li>Let <var>script</var> be <var>serviceWorker</var>'s <a for="service worker">script resource</a>.</li>
      <li>Assert: <var>script</var> is not null.</li>
      <li>If <var>serviceWorker</var> is already running, abort these steps.</li>
      <li>Create a separate parallel execution environment (i.e. a separate thread or process or equivalent construct), and run the rest of these steps in that context.</li>
      <li>Call the JavaScript <a href="https://tc39.github.io/ecma262/#sec-initializehostdefinedrealm">InitializeHostDefinedRealm()</a> abstract operation with the following customizations:
        <ul>
          <li>For the global object, create a new {{ServiceWorkerGlobalScope}} object. Let <var>workerGlobalScope</var> be the created object.</li>
          <li>Let <var>realmExecutionContext</var> be the created <a href="https://tc39.github.io/ecma262/#sec-execution-contexts">JavaScript execution context</a>.</li>
        </ul>
      </li>
      <li>Let <var>workerEventLoop</var> be a newly created <a>event loop</a>.</li>
      <li>Let <var>workerGlobalScope</var> be <var>realmExecutionContext</var>'s <a>global object</a>.</li>
      <li>Let <var>settingsObject</var> be a new <a>environment settings object</a> whose algorithms are defined as follows:
        <dl>
          <dt>The <a>realm execution context</a></dt>
          <dd>Return <var>realmExecutionContext</var>.</dd>
          <dt>The <a>global object</a></dt>
          <dd>Return <var>workerGlobalScope</var>.</dd>
          <dt>The <a>responsible event loop</a></dt>
          <dd>Return <var>workerEventLoop</var>.</dd>
          <dt>The <a>referrer source</a></dt>
          <dd>Return <var>serviceWorker</var>'s <a href="#dfn-script-url">script url</a>.</dd>
          <p class="issue">Remove this definition after sorting out the referencing sites.</p>
          <dt>The <a>API URL character encoding</a></dt>
          <dd>Return UTF-8.</dd>
          <dt>The <a>API base URL</a></dt>
          <dd>Return <var>serviceWorker</var>'s <a href="#dfn-script-url">script url</a>.</dd>
          <dt>The <a for="resource">origin</a></dt>
          <dd>Return its registering <a href="#dfn-service-worker-client">service worker client</a>'s <a for="resource">origin</a>.</dd>
          <dt>The <a>creation URL</a></dt>
          <dd>Return <var>workerGlobalScope</var>'s <a for="workerglobalscope">url</a>.</dd>
          <dt>The <a for="environment settings object">HTTPS state</a></dt>
          <dd>Return <var>workerGlobalScope</var>'s <a for="workerglobalscope">HTTPS state</a>.</dd>
        </dl>
      </li>
      <li>Set <var>workerGlobalScope</var>'s <a for="workerglobalscope">url</a> to <var>serviceWorker</var>'s <a href="#dfn-script-url">script url</a>.</li>
      <li>Set <var>workerGlobalScope</var>'s <a for="workerglobalscope">HTTPS state</a> to <var>serviceWorker</var>'s <a>script resource</a>'s <a href="#dfn-https-state">HTTPS state</a>.</li>
      <li>Set <var>workerGlobalScope</var>'s <a for="workerglobalscope">type</a> to <var>serviceWorker</var>'s <a href="#dfn-type">type</a>.</li>
      <li>Create a new {{WorkerLocation}} object and associate it with <var>workerGlobalScope</var>.</li>
      <li>If <var>serviceWorker</var> is an <a href="#dfn-active-worker">active worker</a>, and there are any <a>tasks</a> queued in <var>serviceWorker</var>'s <a href="#dfn-containing-service-worker-registration">containing service worker registration</a>'s <a href="#dfn-service-worker-registration-task-queue">task queues</a>, <a lt="queue a task">queue</a> them to <var>serviceWorker</var>'s <a>event loop</a>'s <a for="event loop">task queues</a> in the same order using their original <a>task sources</a>.</li>
      <li>If <var>script</var> is a <a>classic script</a>, then <a lt="run a classic script">run the classic script</a> <var>script</var>. Otherwise, it is a <a>module script</a>; <a lt="run a module script">run the module script</a> <var>script</var>.
        <p class="note">In addition to the usual possibilities of returning a value or failing due to an exception, this could be prematurely aborted by the <a>kill a worker</a> or <a>terminate a worker</a> algorithms.</p>
      </li>
      <li>If <var>script</var>'s <a href="#dfn-has-ever-been-evaluated-flag">has ever been evaluated flag</a> is unset, then:
        <ol>
          <li>Set <var>workerGlobalScope</var>'s associated <a href="#dfn-service-worker-global-scope-service-worker">service worker</a>'s <a href="#dfn-set-of-event-types-to-handle">set of event types to handle</a> to the set of event types created from <var>settingsObject</var>'s <a>global object</a>'s associated list of <a>event listeners</a>' event types.
            <p class="note">If the global object's associated list of event listeners does not have any event listener added at this moment, the service worker's set of event types to handle is set to an empty set. The user agents are encouraged to show a warning that the event listeners must be added on the very first evaluation of the worker script.</p>
          </li>
          <li>Set <var>script</var>'s <a href="#dfn-has-ever-been-evaluated-flag">has ever been evaluated flag</a>.</li>
        </ol>
      </li>
      <li>Run the <a>responsible event loop</a> specified by <var>settingsObject</var> until it is destroyed.</li>
      <li>Empty <var>workerGlobalScope</var>'s <a>list of active timers</a>.</li>
    </ol>
  </section>

  <section algorithm="terminate-service-worker-algorithm">
    <h3 id="terminate-service-worker-algorithm">Terminate Service Worker</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>serviceWorker</var>, a <a href="#dfn-service-worker">service worker</a></dd>
      <dt>Output</dt>
        <dd>None</dd>
    </dl>
    <ol>
      <li>If <var>serviceWorker</var> is not running, abort these steps.</li>
      <li>Let <var>serviceWorkerGlobalScope</var> be <var>serviceWorker</var>'s <a>environment settings object</a>'s <a>global object</a>.</li>
      <li>Set <var>serviceWorkerGlobalScope</var>'s closing flag to true.</li>
      <li>If there are any <a>tasks</a>, whose <a>task source</a> is either the <a href="#dfn-handle-fetch-task-source">handle fetch task source</a> or the <a href="#dfn-handle-functional-event-task-source">handle functional event task source</a>, queued in <var>serviceWorkerGlobalScope</var>'s <a>event loop</a>'s <a for="event loop">task queues</a>, <a lt="queue a task">queue</a> them to <var>serviceWorker</var>'s <a href="#dfn-containing-service-worker-registration">containing service worker registration</a>'s corresponding <a href="#dfn-service-worker-registration-task-queue">task queues</a> in the same order using their original <a>task sources</a>, and discard all the <a>tasks</a> (including <a>tasks</a> whose <a>task source</a> is neither the <a href="#dfn-handle-fetch-task-source">handle fetch task source</a> nor the <a href="#dfn-handle-functional-event-task-source">handle functional event task source</a>) from <var>serviceWorkerGlobalScope</var>'s <a>event loop</a>'s <a for="event loop">task queues</a> without processing them.
        <p class="note">This effectively means that the fetch events and the other functional events such as push events are backed up by the registration's task queues while the other tasks including message events are discarded.</p>
      </li>
      <li>Abort the script currently running in <var>serviceWorker</var>.</li>
    </ol>
  </section>

  <section algorithm="on-fetch-request-algorithm">
    <h3 id="on-fetch-request-algorithm">Handle Fetch</h3>

    <p>The <a href="#on-fetch-request-algorithm">Handle Fetch</a> algorithm is the entry point for the <a>fetch</a> handling handed to the <a href="#dfn-service-worker">service worker</a> context.</p>

    <dl>
      <dt>Input</dt>
        <dd><var>request</var>, a <a for="fetch">request</a></dd>
      <dt>Output</dt>
        <dd><var>response</var>, a <a for="fetch">response</a></dd>
    </dl>
    <ol link-for-hint="FetchEvent">
      <li>Let <var>handleFetchFailed</var> be false.</li>
      <li>Let <var>respondWithEntered</var> be false.</li>
      <li>Let <var>eventCanceled</var> be false.</li>
      <li>Let <var>r</var> be a new {{Request}} object associated with <var>request</var>.</li>
      <li>Let <var>headersObject</var> be <var>r</var>'s {{Request/headers}} attribute value.</li>
      <li>Set <var>headersObject</var>'s <a for="headers">guard</a> to <em>immutable</em>.</li>
      <li>Let <var>response</var> be null.</li>
      <li>Let <var>registration</var> be null.</li>
      <li>Let <var>client</var> be the <a href="#dfn-service-worker-client">service worker client</a> that corresponds to <var>request</var>'s <a for="request">client</a>.</li>
      <li>Assert: <var>request</var>'s <a for="request">destination</a> is not "<code>serviceworker</code>".</li>
      <li>If <var>request</var> is a <a>potential-navigation-or-subresource request</a>, then:
        <ol>
          <li>Return null.</li>
        </ol>
      </li>
      <li>Else if <var>request</var> is a <a>non-subresource request</a>, then:
        <p class="note">If the non-subresource request is under the scope of a service worker registration, application cache is completely bypassed regardless of whether the non-subresource request uses the service worker registration.</p>
        <ol>
          <li>If <var>client</var> is not a <a>secure context</a>, return null.</li>
          <li>If <var>request</var> is a <a>navigation request</a> and the <a lt="navigate">navigation</a> triggering it was initiated with a shift+reload or equivalent, return null.</li>
          <li>Set <var>registration</var> to the result of running <a href="#scope-match-algorithm">Match Service Worker Registration</a> algorithm passing <var>request</var>'s <a for="request">url</a> as the argument.</li>
          <li>If <var>registration</var> is null or <var>registration</var>'s <a href="#dfn-active-worker">active worker</a> is null, return null.</li>
          <li>Set <var>client</var>'s <a href="#dfn-service-worker-client-active-worker">active worker</a> to <var>registration</var>'s <a href="#dfn-active-worker">active worker</a>.</li>
        </ol>
        <p class="note">From this point, the <a href="#dfn-service-worker-client">service worker client</a> starts to <a href="#dfn-use">use</a> its <a href="#dfn-service-worker-client-active-worker">active worker</a>'s <a href="#dfn-containing-service-worker-registration">containing service worker registration</a>.</p>
      </li>
      <li>Else if <var>request</var> is a <a>subresource request</a>, then:
        <ol>
          <li>If <var>client</var>'s <a href="#dfn-service-worker-client-active-worker">active worker</a> is non-null, set <var>registration</var> to <var>client</var>'s <a href="#dfn-service-worker-client-active-worker">active worker</a>'s <a href="#dfn-containing-service-worker-registration">containing service worker registration</a>.</li>
          <li>Else, return null.</li>
        </ol>
      </li>
      <li>Let <var>activeWorker</var> be <var>registration</var>'s <a href="#dfn-active-worker">active worker</a>.</li>
      <li>If <var>activeWorker</var>'s <a href="#dfn-set-of-event-types-to-handle">set of event types to handle</a> does not contain <code>fetch</code>, return null.
        <p class="note">To avoid unnecessary delays, the Handle Fetch enforces early return when no event listeners have been deterministically added in the service worker's global during the very first script execution.</p>
      </li>
      <li>If <var>activeWorker</var>'s <a href="#dfn-state">state</a> is <em>activating</em>, wait for <var>activeWorker</var>'s <a href="#dfn-state">state</a> to become <em>activated</em>.</li>
      <li>Invoke <a href="#run-service-worker-algorithm">Run Service Worker</a> algorithm with <var>activeWorker</var> as the argument.</li>
      <li><a>Queue a task</a> <var>task</var> to run the following substeps:
        <ol>
          <li>Create a <a>trusted event</a> <var>e</var> that uses the {{FetchEvent}} interface, with the event type <code><a href="#service-worker-global-scope-fetch-event">fetch</a></code>, which does not bubble.</li>
          <li>Let the <a href="#fetch-event-request-attribute">request</a> attribute of <var>e</var> be initialized to <var>r</var>.</li>
          <li>Let the <a href="#fetch-event-clientid-attribute">clientId</a> attribute of <var>e</var> be initialized to <var>client</var>'s <a href="#dfn-service-worker-client-id">id</a> if <var>request</var> is not a <a>non-subresource request</a>, and to null otherwise.</li>
          <li>Let the <a href="#fetch-event-isreload-attribute">isReload</a> attribute of <var>e</var> be initialized to <code>true</code> if <var>request</var>'s <a for="request">client</a> is a <a href="#dfn-window-client">window client</a> and the event was dispatched with the user's intention for the page reload, and <code>false</code> otherwise.</li>
          <li><a>Dispatch</a> <var>e</var> at <var>activeWorker</var>'s <a>environment settings object</a>'s <a>global object</a>.</li>
          <li>If <var>e</var>'s <a href="#respond-with-entered-flag">respond-with entered flag</a> is set, set <var>respondWithEntered</var> to true.</li>
          <li>If <var>e</var>'s <a href="#wait-to-respond-flag">wait to respond flag</a> is set, then:
            <ol>
              <li>Wait until <var>e</var>'s <a href="#wait-to-respond-flag">wait to respond flag</a> is unset.</li>
              <li>If <var>e</var>'s <a href="#respond-with-error-flag">respond-with error flag</a> is set, set <var>handleFetchFailed</var> to true.</li>
              <li>Else, set <var>response</var> to <var>e</var>'s <a>potential response</a>.</li>
            </ol>
          </li>
          <li>If <var>e</var>'s <a>canceled flag</a> is set, set <var>eventCanceled</var> to true.</li>
        </ol>
        <p>If <var>task</var> is discarded or the script has been aborted by the <a href="#terminate-service-worker-algorithm">termination</a> of <var>activeWorker</var>, set <var>handleFetchFailed</var> to true.</p>
        <p>The <var>task</var> <em class="rfc2119" title="MUST">must</em> use <var>activeWorker</var>'s <a>event loop</a> and the <a href="#dfn-handle-fetch-task-source">handle fetch task source</a>.</p>
      </li>
      <li>Wait for <var>task</var> to have executed or been discarded.</li>
      <li>If <var>respondWithEntered</var> is false, then:
        <ol>
          <li>If <var>eventCanceled</var> is true, return a <a>network error</a> and continue running these substeps <a>in parallel</a>.</li>
          <li>Else, return null and continue running these substeps <a>in parallel</a>.</li>
          <li>If <var>request</var> is a <a>non-subresource request</a>, or <var>request</var> is a <a>subresource request</a> and the time difference in seconds calculated by the current time minus <var>registration</var>'s <a href="#dfn-last-update-check-time">last update check time</a> is greater than 86400, invoke <a href="#soft-update-algorithm">Soft Update</a> algorithm with <var>registration</var>.</li>
          <li>Abort these steps.</li>
        </ol>
      </li>
      <li>If <var>handleFetchFailed</var> is true, then:
        <ol>
          <li>Return a <a>network error</a> and continue running these substeps <a>in parallel</a>.</li>
          <li>If <var>request</var> is a <a>non-subresource request</a>, or <var>request</var> is a <a>subresource request</a> and the time difference in seconds calculated by the current time minus <var>registration</var>'s <a href="#dfn-last-update-check-time">last update check time</a> is greater than 86400, invoke <a href="#soft-update-algorithm">Soft Update</a> algorithm with <var>registration</var>.</li>
        </ol>
      </li>
      <li>Else:
        <ol>
          <li>Return <var>response</var> and continue running these substeps <a>in parallel</a>.</li>
          <li>If <var>request</var> is a <a>non-subresource request</a>, or <var>request</var> is a <a>subresource request</a> and the time difference in seconds calculated by the current time minus <var>registration</var>'s <a href="#dfn-last-update-check-time">last update check time</a> is greater than 86400, invoke <a href="#soft-update-algorithm">Soft Update</a> algorithm with <var>registration</var>.</li>
        </ol>
      </li>
    </ol>
  </section>

  <section algorithm="on-foreign-fetch-request-algorithm">
    <h3 id="on-foreign-fetch-request-algorithm">Handle Foreign Fetch</h3>

    <p>The [[#on-foreign-fetch-request-algorithm]] algorithm is the entry point for the <a>fetch</a> handling handed to the <a href="#dfn-service-worker">service worker</a> context to handle foreign fetch requests.</p>

    <dl>
      <dt>Input</dt>
        <dd><var>request</var>, a  <a for="fetch">request</a></dd>
      <dt>Output</dt>
        <dd><var>response</var>, a <a for="fetch">response</a></dd>
    </dl>
    <ol link-for-hint="ForeignFetchEvent">
      <li>Let <var>handleFetchFailed</var> be false.</li>
      <li>Let <var>respondWithEntered</var> be false.</li>
      <li>Let <var>eventCanceled</var> be false.</li>
      <li>If <var>request</var> is not a <a>subresource request</a>, return null and abort these steps.
        <p class="note">Foreign fetch only allows intercepting of subresource requests. Navigation requests can be intercepted by the regular fetch event anyway, so there is no benefit to supporting those requests here as well.</p>
      </li>
      <li>If <var>request</var>'s <a for="request">client</a> is not a <a>secure context</a>, return null and abort these steps.</li>
      <li>Let <var>activeWorker</var> be the result of running the [[#foreign-fetch-scope-match-algorithm]] algorithm passing <var>request</var>'s <a for="request">url</a> as the argument.</li>
      <li>If <var>activeWorker</var> is null, return null.</li>
      <li>If <var>activeWorker</var>'s <a href="#dfn-state">state</a> is <em>activating</em>, then:
        <ol>
          <li>Wait for <var>activeWorker</var>'s <a href="#dfn-state">state</a> to become <em>activated</em>.</li>
        </ol>
      </li>
      <li>If <var>activeWorker</var>'s <a for="resource">origin</a> is the same as <var>request</var>'s <a for="request">origin</a>, return null.</li>
      <li>Let <var>originMatches</var> be false.</li>
      <li>If <var>activeWorker</var>'s <a>list of foreign fetch origins</a> is empty, set <var>originMatches</var> to true.</li>
      <li>For each <var>origin</var> in <var>activeWorker</var>'s <a>list of foreign fetch origins</a>:
        <ol>
          <li>If <var>origin</var> is equal to <var>request</var>'s <a for="request">origin</a>, set <var>originMatches</var> to true.</li>
        </ol>
      </li>
      <li>If <var>originMatches</var> is false, return null.</li>
      <li>Let <var>r</var> be a new {{Request}} object associated with <var>request</var>.</li>
      <li>Invoke [[#run-service-worker-algorithm]] algorithm with <var>activeWorker</var> as the argument.</li>
      <li><a>Queue a task</a> <var>task</var> to run the following substeps:
        <ol>
          <li>Create a <a>trusted event</a> <var>e</var> that uses the {{ForeignFetchEvent}} interface, with the event type <code><a href="#service-worker-global-scope-foreignfetch-event">foreignfetch</a></code>, which does not bubble.</li>
          <li>Let the {{ForeignFetchEvent/request}} attribute of <var>e</var> be initialized to <var>r</var>.</li>
          <li>Let the {{ForeignFetchEvent/origin}} attribute of <var>e</var> be initialized to the  <a lt="Unicode serialisation of an origin">Unicode serialization</a> of <var>request</var>'s <a for=request>origin</a>.</li>
          <li><a>Dispatch</a> <var>e</var> at <var>activeWorker</var>'s <a>environment settings object</a>'s <a>global object</a>.</li>
          <li>If <var>e</var>'s <a>respond-with entered flag</a> is set, set <var>respondWithEntered</var> to true.</li>
          <li>If <var>e</var>'s <a>wait to respond flag</a> is set, wait until <var>e</var>'s <a>wait to respond flag</a> is unset.</li>
          <li>Let <var>internalResponse</var> be <var>e</var>'s <a>potential response</a>.</li>
          <li>If <var>internalResponse</var> is a <a>filtered response</a>, set <var>internalResponse</var> to <var>internalResponse</var>'s <a>internal response</a>.</li>
          <li>If <var>e</var>'s <a>respond-with error flag</a> is set, set <var>handleFetchFailed</var> to true.</li>
          <li>Else if <var>e</var>'s <a>origin</a> is null:
            <ol>
              <li>If <var>e</var>'s <a>list of exposed headers</a> is not empty, set <var>handleFetchFailed</var> to true.</li>
              <li>Else if <var>e</var>'s <a>potential response</a> is a <a>opaque-redirect filtered response</a>, set <var>response</var> to <var>e</var>'s <a>potential response</a>.</li>
              <li>Else set <var>response</var> to an <a>opaque filtered response</a> of <var>internalResponse</var>.</li>
            </ol>
          </li>
          <li>Else if <var>e</var>'s <a>origin</a> is not equal to the <a lt="Unicode serialisation of an origin">Unicode serialization</a> of <var>request</var>'s <a for="request">origin</a>, set <var>handleFetchFailed</var> to true.</li>
          <li>Else if <var>e</var>'s <a>potential response</a> is an <a>opaque filtered response</a> or is an <a>opaque-redirect filtered response</a>, set <var>response</var> to <var>e</var>'s <a>potential response</a>.</li>
          <li>Else if <var>request</var>'s <a>response tainting</a> is <code>"opaque"</code>, set <var>response</var> to an <a>opaque filtered response</a> of <var>internalResponse</var>.</li>
          <li>Else:
            <ol>
              <li>Let <var>headers</var> be <var>e</var>'s <a>list of exposed headers</a>.</li>
              <li>If <var>response</var> is a <a>CORS filtered response</a>, remove from <var>internalResponse</var>'s <a>CORS-exposed header-name list</a> all values not in <var>headers</var>.</li>
              <li>Else set <var>internalResponse</var>'s <a>CORS-exposed header-name list</a> to <var>headers</var>.</li>
              <li>Set <var>response</var> to a <a>CORS filtered response</a> of <var>internalResponse</var>.</li>
            </ol>
          </li>
          <li>If <var>e</var>'s <a>canceled flag</a> is set, set <var>eventCanceled</var> to true.</li>
        </ol>
        <p>If <var>task</var> is discarded or the script has been aborted by the <a href="#terminate-service-worker-algorithm">termination</a> of <var>activeWorker</var>, set <var>handleFetchFailed</var> to true.</p>
        <p>The <var>task</var> <em class="rfc2119" title="MUST">must</em> use <var>activeWorker</var>'s <a>event loop</a> and the <a>handle fetch task source</a>.</p>
      </li>
      <li>Wait for <var>task</var> to have executed or been discarded.</li>
      <li>If <var>respondWithEntered</var> is false, then:
        <ol>
          <li>If <var>eventCanceled</var> is true, then:
            <ol>
              <li>Return a <a>network error</a>.</li>
            </ol>
          </li>
          <li>Else:
            <ol>
              <li>Return null.</li>
            </ol>
          </li>
        </ol>
      </li>
      <li>If <var>handleFetchFailed</var> is true, then:
        <ol>
          <li>Return a <a>network error</a>.</li>
        </ol>
      </li>
      <li>Else:
        <ol>
          <li>Return <var>response</var>.</li>
        </ol>
      </li>
    </ol>
  </section>

  <section algorithm="handle-functional-event-algorithm">
    <h3 id="handle-functional-event-algorithm">Handle Functional Event</h3>

    <dl>
    <dt>Input</dt>
        <dd><var>registration</var>, a <a href="#dfn-service-worker-registration">service worker registration</a></dd>
        <dd><var>callbackSteps</var>, an algorithm</dd>
    <dt>Output</dt>
        <dd>None</dd>
    </dl>
    <ol>
      <li><a>Assert</a>: a <a>Record</a> with the \[[value]] equals to <var>registration</var> is contained in <a href="#dfn-scope-to-registration-map">scope to registration map</a>.</li>
      <li><a>Assert</a>: <var>registration</var>'s <a href="#dfn-active-worker">active worker</a> is not null.</li>
      <li>Let <var>activeWorker</var> be <var>registration</var>'s <a href="#dfn-active-worker">active worker</a>.</li>
      <li>If <var>activeWorker</var>'s <a href="#dfn-set-of-event-types-to-handle">set of event types to handle</a> does not contain the event type for this functional event, return.
        <p class="note">To avoid unnecessary delays, the Handle Functional Event enforces early return when no event listeners have been deterministically added in the service worker's global during the very first script execution.</p>
      </li>
      <li>If <var>activeWorker</var>'s <a href="#dfn-state">state</a> is <em>activating</em>, wait for <var>activeWorker</var>'s <a href="#dfn-state">state</a> to become <em>activated</em>.</li>
      <li>Invoke <a href="#run-service-worker-algorithm">Run Service Worker</a> algorithm with <var>activeWorker</var> as the argument.</li>
      <li><a>Queue a task</a> <var>task</var> to invoke <var>callbackSteps</var> with <var>activeWorker</var>'s <a>environment settings object</a>'s <a>global object</a> as its argument.
        <p>The <var>task</var> <em class="rfc2119" title="MUST">must</em> use <var>activeWorker</var>'s <a>event loop</a> and the <a href="#dfn-handle-functional-event-task-source">handle functional event task source</a>.</p>
      </li>
      <li>Wait for <var>task</var> to have executed or been discarded.</li>
      <li>If the time difference in seconds calculated by the current time minus <var>registration</var>'s <a href="#dfn-last-update-check-time">last update check time</a> is greater than 86400, invoke <a href="#soft-update-algorithm">Soft Update</a> algorithm with <var>registration</var>.</li>
    </ol>
  </section>

  <section algorithm="on-client-unload-algorithm">
    <h3 id="on-client-unload-algorithm">Handle Service Worker Client Unload</h3>

    <p>The user agent <em class="rfc2119" title="MUST">must</em> run these steps when a <a href="#dfn-service-worker-client">service worker client</a> unloads by <a lt="unload a document">unloading</a>, <a lt="kill a worker">being killed</a>, or <a href="#terminate-service-worker-algorithm">terminating</a>.</p>

    <dl>
    <dt>Input</dt>
        <dd><var>client</var>, a <a href="#dfn-service-worker-client">service worker client</a></dd>
    <dt>Output</dt>
        <dd>None</dd>
    </dl>
    <ol>
      <li>Run the following steps atomically.</li>
      <li>Let <var>registration</var> be the <a href="#dfn-service-worker-registration">service worker registration</a> <a href="#dfn-use">used</a> by <var>client</var>.</li>
      <li>If <var>registration</var> is null, abort these steps.</li>
      <li>If any other <a href="#dfn-service-worker-client">service worker client</a> is <a href="#dfn-use">using</a> <var>registration</var>, abort these steps.</li>
      <li>If <var>registration</var>'s <a href="#dfn-uninstalling-flag">uninstalling flag</a> is set, invoke <a href="#clear-registration-algorithm">Clear Registration</a> algorithm passing <var>registration</var> as its argument and abort these steps.</li>
      <li>If <var>registration</var>'s <a href="#dfn-waiting-worker">waiting worker</a> is not null, run <a href="#activation-algorithm">Activate</a> algorithm with <var>registration</var> as the argument.</li>
    </ol>
  </section>

  <section algorithm="on-user-agent-shutdown-algorithm">
    <h3 id="on-user-agent-shutdown-algorithm">Handle User Agent Shutdown</h3>

    <dl>
    <dt>Input</dt>
        <dd>None</dd>
    <dt>Output</dt>
        <dd>None</dd>
    </dl>
    <ol>
      <li>For each <a>Record</a> {\[[key]], \[[value]]} <var>entry</var> of its <a href="#dfn-scope-to-registration-map">scope to registration map</a>:
        <ol>
          <li>Let <var>registration</var> be <var>entry</var>.\[[value]].</li>
          <li>If <var>registration</var>'s <a>installing worker</a> <var>installingWorker</var> is not null, then:
            <ol>
              <li>If the result of running <a href="#get-newest-worker-algorithm">Get Newest Worker</a> with <var>registration</var> is <var>installingWorker</var>, invoke <a href="#clear-registration-algorithm">Clear Registration</a> with <var>registration</var> and continue to the next iteration of the loop.</li>
              <li>Else, set <var>registration</var>'s <a>installing worker</a> to null.</li>
            </ol>
          </li>
          <li>If <var>registration</var>'s <a>waiting worker</a> is not null, run the following substep <a>in parallel</a>:
            <ol>
              <li>Invoke <a href="#activation-algorithm">Activate</a> with <var>registration</var>.</li>
            </ol>
          </li>
        </ol>
      </li>
    </ol>
  </section>

  <section algorithm="unregister-algorithm">
    <h3 id="unregister-algorithm">Unregister</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>job</var>, a <a href="#dfn-job">job</a></dd>
      <dt>Output</dt>
        <dd>none</dd>
    </dl>
    <ol>
      <li>If the <a for="resource">origin</a> of <var>job</var>'s <a href="#dfn-job-scope-url">scope url</a> is not <var>job</var>'s <a href="#dfn-job-client">client</a>'s <a for="resource">origin</a>, then:
        <ol>
          <li>Invoke <a href="#reject-job-promise-algorithm">Reject Job Promise</a> with <var>job</var> and a "{{SecurityError}}" exception.</li>
          <li>Invoke <a href="#finish-job-algorithm">Finish Job</a> with <var>job</var> and abort these steps.</li>
        </ol>
      </li>
      <li>Let <var>registration</var> be the result of running <a href="#get-registration-algorithm">Get Registration</a> algorithm passing <var>job</var>'s <a href="#dfn-job-scope-url">scope url</a> as the argument.</li>
      <li>If <var>registration</var> is null, then:
        <ol>
          <li>Invoke <a href="#resolve-job-promise-algorithm">Resolve Job Promise</a> with <var>job</var> and false.</li>
          <li>Invoke <a href="#finish-job-algorithm">Finish Job</a> with <var>job</var> and abort these steps.</li>
        </ol>
      </li>
      <li>Set <var>registration</var>'s <a href="#dfn-uninstalling-flag">uninstalling flag</a>.</li>
      <li>Invoke <a href="#resolve-job-promise-algorithm">Resolve Job Promise</a> with <var>job</var> and true.</li>
      <li>If no <a href="#dfn-service-worker-client">service worker client</a> is <a href="#dfn-use">using</a> <var>registration</var>, invoke <a href="#clear-registration-algorithm">Clear Registration</a> algorithm passing <var>registration</var> as its argument.
        <p class="note">When the registration is being used for a client, the deletion of the registration is handled by the Handle Service Worker Client Unload algorithm.</p>
      </li>
      <li>Invoke <a href="#finish-job-algorithm">Finish Job</a> with <var>job</var>.</li>
    </ol>
  </section>

  <section algorithm="set-registration-algorithm">
    <h3 id="set-registration-algorithm">Set Registration</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>scope</var>, a <a for="url">URL</a></dd>
      <dt>Output</dt>
        <dd><var>registration</var>, a <a href="#dfn-service-worker-registration">service worker registration</a></dd>
    </dl>
    <ol>
      <li>Run the following steps atomically.</li>
      <li>Let <var>scopeString</var> be <a for="url">serialized</a> <var>scope</var> with the <em>exclude fragment flag</em> set.</li>
      <li>Let <var>registration</var> be a new <a href="#dfn-service-worker-registration">service worker registration</a> whose <a href="#dfn-scope-url">scope url</a> is set to <var>scope</var>.</li>
      <li>Set a newly-created <a>Record</a> {\[[key]]: <var>scopeString</var>, \[[value]]: <var>registration</var>} to <a href="#dfn-scope-to-registration-map">scope to registration map</a>.</li>
      <li>Return <var>registration</var>.</li>
    </ol>
  </section>

  <section algorithm="clear-registration-algorithm">
    <h3 id="clear-registration-algorithm">Clear Registration</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>registration</var>, a <a href="#dfn-service-worker-registration">service worker registration</a></dd>
      <dt>Output</dt>
        <dd>None</dd>
    </dl>
    <ol>
      <li>Run the following steps atomically.</li>
      <li>Let <var>redundantWorker</var> be null.</li>
      <li>If <var>registration</var>'s <a href="#dfn-installing-worker">installing worker</a> is not null, then:
        <ol>
          <li>Set <var>redundantWorker</var> to <var>registration</var>'s <a href="#dfn-installing-worker">installing worker</a>.</li>
          <li><a href="#terminate-service-worker-algorithm">Terminate</a> <var>redundantWorker</var>.</li>
          <li>The user agent <em class="rfc2119" title="MAY">may</em> abort in-flight requests triggered by <var>redundantWorker</var>.</li>
          <li>Run the <a href="#update-registration-state-algorithm">Update Registration State</a> algorithm passing <var>registration</var>, "<code>installing</code>" and null as the arguments.</li>
          <li>Run the <a href="#update-state-algorithm">Update Worker State</a> algorithm passing <var>redundantWorker</var> and <em>redundant</em> as the arguments.</li>
        </ol>
      </li>
      <li>If <var>registration</var>'s <a href="#dfn-waiting-worker">waiting worker</a> is not null, then:
        <ol>
          <li>Set <var>redundantWorker</var> to <var>registration</var>'s <a href="#dfn-waiting-worker">waiting worker</a>.</li>
          <li><a href="#terminate-service-worker-algorithm">Terminate</a> <var>redundantWorker</var>.</li>
          <li>The user agent <em class="rfc2119" title="MAY">may</em> abort in-flight requests triggered by <var>redundantWorker</var>.</li>
          <li>Run the <a href="#update-registration-state-algorithm">Update Registration State</a> algorithm passing <var>registration</var>, "<code>waiting</code>" and null as the arguments.</li>
          <li>Run the <a href="#update-state-algorithm">Update Worker State</a> algorithm passing <var>redundantWorker</var> and <em>redundant</em> as the arguments.</li>
        </ol>
      </li>
      <li>If <var>registration</var>'s <a href="#dfn-active-worker">active worker</a> is not null, then:
        <ol>
          <li>Set <var>redundantWorker</var> to <var>registration</var>'s <a href="#dfn-active-worker">active worker</a>.</li>
          <li><a href="#terminate-service-worker-algorithm">Terminate</a> <var>redundantWorker</var>.</li>
          <li>The user agent <em class="rfc2119" title="MAY">may</em> abort in-flight requests triggered by <var>redundantWorker</var>.</li>
          <li>Run the <a href="#update-registration-state-algorithm">Update Registration State</a> algorithm passing <var>registration</var>, "<code>active</code>" and null as the arguments.</li>
          <li>Run the <a href="#update-state-algorithm">Update Worker State</a> algorithm passing <var>redundantWorker</var> and <em>redundant</em> as the arguments.</li>
        </ol>
      </li>
      <li>Delete a <a>Record</a> {\[[key]], \[[value]]} <var>entry</var> from <a href="#dfn-scope-to-registration-map">scope to registration map</a> where <var>registration</var>'s <a href="#dfn-scope-url">scope url</a> is the result of <a for="url">parsing</a> <var>entry</var>.\[[key]].</li>
    </ol>
  </section>

  <section algorithm="update-registration-state-algorithm">
    <h3 id="update-registration-state-algorithm">Update Registration State</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>registration</var>, a <a href="#dfn-service-worker-registration">service worker registration</a></dd>
        <dd><var>target</var>, a string (one of "<code>installing</code>", "<code>waiting</code>", and "<code>active</code>")</dd>
        <dd><var>source</var>, a <a href="#dfn-service-worker">service worker</a> or null</dd>
      <dt>Output</dt>
        <dd>None</dd>
    </dl>
    <ol>
      <li>Let <var>registrationObjects</var> be an array containing all the {{ServiceWorkerRegistration}} objects associated with <var>registration</var>.</li>
      <li>If <var>target</var> is "<code>installing</code>", then:
        <ol>
          <li>Set <var>registration</var>'s <a>installing worker</a> to <var>source</var>.</li>
          <li>For each <var>registrationObject</var> in <var>registrationObjects</var>:
            <ol>
              <li><a>Queue a task</a> to set the <a href="#service-worker-registration-installing-attribute">installing</a> attribute of <var>registrationObject</var> to the {{ServiceWorker}} object that represents <var>registration</var>’s <a>installing worker</a>, or null if <var>registration</var>’s <a>installing worker</a> is null.</li>
            </ol>
          </li>
        </ol>
      </li>
      <li>Else if <var>target</var> is "<code>waiting</code>", then:
        <ol>
          <li>Set <var>registration</var>'s <a>waiting worker</a> to <var>source</var>.</li>
          <li>For each <var>registrationObject</var> in <var>registrationObjects</var>:
            <ol>
              <li><a>Queue a task</a> to set the <a href="#service-worker-registration-waiting-attribute">waiting</a> attribute of <var>registrationObject</var> to the {{ServiceWorker}} object that represents <var>registration</var>’s <a>waiting worker</a>, or null if <var>registration</var>’s <a>waiting worker</a> is null.</li>
            </ol>
          </li>
        </ol>
      </li>
      <li>Else if <var>target</var> is "<code>active</code>", then:
        <ol>
          <li>Set <var>registration</var>'s <a for="service worker registration">active worker</a> to <var>source</var>.</li>
          <li>For each <var>registrationObject</var> in <var>registrationObjects</var>:
            <ol>
              <li><a>Queue a task</a> to set the <a href="#service-worker-registration-active-attribute">active</a> attribute of <var>registrationObject</var> to the {{ServiceWorker}} object that represents <var>registration</var>’s <a for="service worker registration">active worker</a>, or null if <var>registration</var>’s <a for="service worker registration">active worker</a> is null.</li>
            </ol>
          </li>
        </ol>
        <p>The <a>task</a> <em class="rfc2119" title="MUST">must</em> use <var>registrationObject</var>'s <a>relevant settings object</a>'s <a>responsible event loop</a> and the <a>DOM manipulation task source</a>.</p>
      </li>
    </ol>
  </section>

  <section algorithm="update-state-algorithm">
    <h3 id="update-state-algorithm">Update Worker State</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>worker</var>, a <a href="#dfn-service-worker">service worker</a></dd>
        <dd><var>state</var>, a <a href="#dfn-service-worker">service worker</a>'s <a href="#dfn-state">state</a></dd>
      <dt>Output</dt>
        <dd>None</dd>
    </dl>
    <ol>
      <li>Set <var>worker</var>'s <a href="#dfn-state">state</a> to <var>state</var>.</li>
      <li>Let <var>workerObjects</var> be an array containing all the <code><a href="#service-worker-interface">ServiceWorker</a></code> objects associated with <var>worker</var>.</li>
      <li>For each <var>workerObject</var> in <var>workerObjects</var>:
        <ol>
          <li><a>Queue a task</a> to run these substeps:
            <ol>
              <li>Set the <a href="#service-worker-state-attribute">state</a> attribute of <var>workerObject</var> to the value (in {{ServiceWorkerState}} enumeration) corresponding to the first matching statement, switching on <var>worker</var>'s <a href="#dfn-state">state</a>:
                <dl>
                  <dt><em>installing</em></dt>
                  <dd>"<code>installing</code>"
                  <p class="note">The <a href="#dfn-service-worker">service worker</a> in this state is considered an <a href="#dfn-installing-worker">installing worker</a>. During this state, <code><a href="#extendable-event-waituntil-method">event.waitUntil(<var>f</var>)</a></code> can be called inside the <code><a href="#service-worker-global-scope-oninstall-attribute">oninstall</a></code> <a>event handler</a> to extend the life of the <a href="#dfn-installing-worker">installing worker</a> until the passed <a>promise</a> resolves successfully. This is primarily used to ensure that the <a href="#dfn-service-worker">service worker</a> is not active until all of the core caches are populated.</p></dd>

                  <dt><em>installed</em></dt>
                  <dd>"<code>installed</code>"
                  <p class="note">The <a href="#dfn-service-worker">service worker</a> in this state is considered a <a href="#dfn-waiting-worker">waiting worker</a>.</p></dd>

                  <dt><em>activating</em></dt>
                  <dd>"<code>activating</code>"
                  <p class="note">The <a href="#dfn-service-worker">service worker</a> in this state is considered an <a href="#dfn-active-worker">active worker</a>. During this state, <code><a href="#extendable-event-waituntil-method">event.waitUntil(<var>f</var>)</a></code> can be called inside the <code><a href="#service-worker-global-scope-onactivate-attribute">onactivate</a></code> <a>event handler</a> to extend the life of the <a href="#dfn-active-worker">active worker</a> until the passed <a>promise</a> resolves successfully. No <a href="#dfn-functional-events">functional events</a> are dispatched until the state becomes <em>activated</em>.</p></dd>

                  <dt><em>activated</em></dt>
                  <dd>"<code>activated</code>"
                  <p class="note">The <a href="#dfn-service-worker">service worker</a> in this state is considered an <a href="#dfn-active-worker">active worker</a> ready to handle <a href="#dfn-functional-events">functional events</a>.</p></dd>

                  <dt><em>redundant</em></dt>
                  <dd>"<code>redundant</code>"
                  <p class="note">A new <a href="#dfn-service-worker">service worker</a> is replacing the current <a href="#dfn-service-worker">service worker</a>, or the current <a href="#dfn-service-worker">service worker</a> is being discarded due to an install failure.</p></dd>
                </dl>
              </li>
              <li><a>Fire a simple event</a> named <code>statechange</code> at <var>workerObject</var>.</li>
            </ol>
          </li>
        </ol>
        <p>The <a>task</a> <em class="rfc2119" title="MUST">must</em> use <var>workerObject</var>'s <a>relevant settings object</a>'s <a>responsible event loop</a> and the <a>DOM manipulation task source</a>.</p>
      </li>
    </ol>
  </section>

  <section algorithm="notify-controller-change-algorithm">
    <h3 id="notify-controller-change-algorithm">Notify Controller Change</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>client</var>, a <a href="#dfn-service-worker-client">service worker client</a></dd>
      <dt>Output</dt>
        <dd>None</dd>
    </dl>
    <ol>
      <li><a>Assert</a>: <var>client</var> is not null.</li>
      <li><a>Queue a task</a> to <a>fire a simple event</a> named <code>controllerchange</code> at the <code><a href="#service-worker-container-interface">ServiceWorkerContainer</a></code> object <var>client</var> is <a href="#dfn-service-worker-container-interface-client">associated</a> with.</li>
    </ol>
    <p>The <a>task</a> <em class="rfc2119" title="MUST">must</em> use <var>client</var>'s <a>responsible event loop</a> and the <a>DOM manipulation task source</a>.</p>
  </section>

  <section algorithm="scope-match-algorithm">
    <h3 id="scope-match-algorithm">Match Service Worker Registration</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>clientURL</var>, a <a for="url">URL</a></dd>
      <dt>Output</dt>
        <dd><var>registration</var>, a <a href="#dfn-service-worker-registration">service worker registration</a></dd>
    </dl>
    <ol>
      <li>Run the following steps atomically.</li>
      <li>Let <var>clientURLString</var> be <a for="url">serialized</a> <var>clientURL</var>.</li>
      <li>Let <var>matchingScope</var> be the empty string.</li>
      <li>Set <var>matchingScope</var> to the longest \[[key]] in <a href="#dfn-scope-to-registration-map">scope to registration map</a> which the value of <var>clientURLString</var> starts with, if it exists.
        <p class="note">The URL string matching in this step is prefix-based rather than path-structural (e.g. a client URL string with "/prefix-of/resource.html" will match a registration for a scope with "/prefix").</p>
      </li>
      <li>Let <var>parsedMatchingScope</var> be null.</li>
      <li>If <var>matchingScope</var> is not the empty string, set <var>parsedMatchingScope</var> to the result of <a for="url">parsing</a> <var>matchingScope</var>.</li>
      <li>Let <var>registration</var> be the result of running <a href="#get-registration-algorithm">Get Registration</a> algorithm passing <var>parsedMatchingScope</var> as the argument.</li>
      <li>If <var>registration</var> is not null and <var>registration</var>'s <a href="#dfn-uninstalling-flag">uninstalling flag</a> is set, return null.</li>
      <li>Return <var>registration</var>.</li>
    </ol>
  </section>

  <section algorithm="foreign-fetch-scope-match-algorithm">
    <h3 id="foreign-fetch-scope-match-algorithm">Match Service Worker for Foreign Fetch</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>requestURL</var>, a <a for="url">URL</a></dd>
      <dt>Output</dt>
        <dd><var>worker</var>, a <a href="#dfn-service-worker">service worker</a></dd>
    </dl>
    <ol>
      <li>Run the following steps atomically.</li>
      <li>Let <var>registration</var> be the result of running the [[#scope-match-algorithm]] algorithm passing <var>requestURL</var> as the argument.</li>
      <li>If <var>registration</var> is null, return null.</li>
      <li>Let <var>worker</var> be <var>registration</var>'s <a for="service worker registration">active worker</a>.</li>
      <li>If <var>worker</var> is null, return null.</li>
      <li>Let <var>requestURLString</var> be the <a for="url">serialized</a> <var>requestURL</var>.</li>
      <li>For each <a for="url">URL</a> <var>scope</var> in <var>worker</var>'s <a>list of foreign fetch scopes</a>:
        <ol>
          <li>Let <var>scopeString</var> be the <a for="url">serialized</a> <var>scope</var>.</li>
          <li>If <var>requestString</var> starts with <var>scopeString</var> return <var>worker</var>.</li>
        </ol>
      </li>
      <li>Return null.</li>
    </ol>
  </section>

  <section algorithm="get-registration-algorithm">
    <h3 id="get-registration-algorithm">Get Registration</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>scope</var>, a <a for="url">URL</a></dd>
      <dt>Output</dt>
        <dd><var>registration</var>, a <a href="#dfn-service-worker-registration">service worker registration</a></dd>
    </dl>
    <ol>
      <li>Run the following steps atomically.</li>
      <li>Let <var>scopeString</var> be the empty string.</li>
      <li>If <var>scope</var> is not null, set <var>scopeString</var> to <a for="url">serialized</a> <var>scope</var> with the <em>exclude fragment flag</em> set.</li>
      <li>Let <var>registration</var> be null.</li>
      <li>For each <a>Record</a> {\[[key]], \[[value]]} <var>entry</var> of its <a href="#dfn-scope-to-registration-map">scope to registration map</a>:
        <ol>
          <li>If <var>scopeString</var> matches <var>entry</var>.\[[key]], set <var>registration</var> to <var>entry</var>.\[[value]].</li>
        </ol>
      </li>
      <li>Return <var>registration</var>.</li>
    </ol>
  </section>

  <section algorithm="get-newest-worker-algorithm">
    <h3 id="get-newest-worker-algorithm">Get Newest Worker</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>registration</var>, a <a href="#dfn-service-worker-registration">service worker registration</a></dd>
      <dt>Output</dt>
        <dd><var>worker</var>, a <a href="#dfn-service-worker">service worker</a></dd>
    </dl>
    <ol>
      <li>Run the following steps atomically.</li>
      <li>Let <var>newestWorker</var> be null.</li>
      <li>If <var>registration</var>'s <a href="#dfn-installing-worker">installing worker</a> is not null, set <var>newestWorker</var> to <var>registration</var>'s <a href="#dfn-installing-worker">installing worker</a>.</li>
      <li>Else if <var>registration</var>'s <a href="#dfn-waiting-worker">waiting worker</a> is not null, set <var>newestWorker</var> to <var>registration</var>'s <a href="#dfn-waiting-worker">waiting worker</a>.</li>
      <li>Else if <var>registration</var>'s <a href="#dfn-active-worker">active worker</a> is not null, set <var>newestWorker</var> to <var>registration</var>'s <a href="#dfn-active-worker">active worker</a>.</li>
      <li>Return <var>newestWorker</var>.</li>
    </ol>
  </section>

  <section algorithm="create-client-algorithm">
    <h3 id="create-client-algorithm">Create Client</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>client</var>, a <a href="#dfn-service-worker-client">service worker client</a></dd>
      <dt>Output</dt>
        <dd><var>clientObject</var>, a {{Client}} object</dd>
    </dl>
    <ol>
      <li>Let <var>clientObject</var> be a new {{Client}} object.</li>
      <li>Set <var>clientObject</var>'s <a href="#dfn-service-worker-client-client">service worker client</a> to <var>client</var>.</li>
      <li>Return <var>clientObject</var>.</li>
    </ol>
  </section>

  <section algorithm="create-windowclient-algorithm">
    <h3 id="create-windowclient-algorithm">Create Window Client</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>client</var>, a <a href="#dfn-service-worker-client">service worker client</a></dd>
        <dd><var>visibilityState</var>, a string</dd>
        <dd><var>focusState</var>, a boolean</dd>
      <dt>Output</dt>
        <dd><var>windowClient</var>, a {{WindowClient}} object</dd>
    </dl>
    <ol>
      <li>Let <var>windowClient</var> be a new {{WindowClient}} object.</li>
      <li>Set <var>windowClient</var>'s <a href="#dfn-service-worker-client-client">service worker client</a> to <var>client</var>.</li>
      <li>Set <var>windowClient</var>'s <a href="#dfn-service-worker-client-visibilitystate">visibility state</a> to <var>visibilityState</var>.</li>
      <li>Set <var>windowClient</var>'s <a href="#dfn-service-worker-client-focusstate">focus state</a> to <var>focusState</var>.</li>
      <li>Return <var>windowClient</var>.</li>
    </ol>
  </section>

  <section algorithm="query-cache-algorithm">
    <h3 id="query-cache-algorithm">Query Cache</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>request</var>, a {{Request}} object</dd>
        <dd><var>options</var>, a {{CacheQueryOptions}} object, optional</dd>
        <dd><var>targetStorage</var>, an array that has [{{Request}}, {{Response}}] pairs as its elements, optional</dd>
      <dt>Output</dt>
        <dd><var>resultArray</var>, an array that has [{{Request}}, {{Response}}] pairs as its elements</dd>
    </dl>
    <ol>
      <li>Let <var>requestArray</var> be an empty array.</li>
      <li>Let <var>responseArray</var> be an empty array.</li>
      <li>Let <var>resultArray</var> be an empty array.</li>
      <li>If <var>options</var>.{{CacheQueryOptions/ignoreMethod}} is false and <var>request</var>.<var>method</var> is not `<code>GET</code>`, return <var>resultArray</var>.</li>
      <li>Let <var>cachedURL</var> and <var>requestURL</var> be null.</li>
      <li>If the optional argument <var>targetStorage</var> is omitted, then:
        <ol>
          <li>For each <a href="#dfn-fetching-record">fetching record</a> <var>entry</var> of its <a href="#dfn-request-to-response-map">request to response map</a>, in key insertion order:
            <ol>
              <li>Set <var>cachedURL</var> to <var>entry</var>.\[[key]]'s associated <a for="request">request</a>'s <a for="request">url</a>.</li>
              <li>Set <var>requestURL</var> to <var>request</var>'s associated <a for="request">request</a>'s <a for="request">url</a>.</li>
              <li>If <var>options</var>.<var>ignoreSearch</var> is true, then:
                <ol>
                  <li>Set <var>cachedURL</var>'s <a for="url">query</a> to the empty string.</li>
                  <li>Set <var>requestURL</var>'s <a for="url">query</a> to the empty string.</li>
                </ol>
              </li>
              <li>If <var>cachedURL</var> <a for="url">equals</a> <var>requestURL</var> with the <em>exclude fragments flag</em> set, then:
                <ol>
                  <li>Add a copy of <var>entry</var>.\[[key]] to <var>requestArray</var>.</li>
                  <li>Add a copy of <var>entry</var>.\[[value]] to <var>responseArray</var>.</li>
                </ol>
              </li>
            </ol>
          </li>
        </ol>
      </li>
      <li>Else:
        <ol>
          <li>For each <var>record</var> in <var>targetStorage</var>:
            <ol>
              <li>Set <var>cachedURL</var> to <var>record</var>[0]'s associated <a for="request">request</a>'s <a for="request">url</a>.</li>
              <li>Set <var>requestURL</var> to <var>request</var>'s associated <a for="request">request</a>'s <a for="request">url</a>.</li>
              <li>If <var>options</var>.{{CacheQueryOptions/ignoreSearch}} is true, then:
                <ol>
                  <li>Set <var>cachedURL</var>'s <a for="url">query</a> to the empty string.</li>
                  <li>Set <var>requestURL</var>'s <a for="url">query</a> to the empty string.</li>
                </ol>
              </li>
              <li>If <var>cachedURL</var> <a for="url">equals</a> <var>requestURL</var> with the <em>exclude fragments flag</em> set, then:
                <ol>
                  <li>Add <var>record</var>[0] to <var>requestArray</var>.</li>
                  <li>Add <var>record</var>[1] to <var>responseArray</var>.</li>
                </ol>
              </li>
            </ol>
          </li>
        </ol>
      </li>
      <li>For each <var>cachedResponse</var> in <var>responseArray</var> with the index <var>index</var>:
        <ol>
          <li>Let <var>cachedRequest</var> be the <var>index</var>th element in <var>requestArray</var>.</li>
          <li>If <var>cachedResponse</var>'s <a for="response">response</a>'s <a for="response">header list</a> contains no <a>header</a> <a for="header">named</a> `<code>Vary</code>`, or <var>options</var>.{{CacheQueryOptions/ignoreVary}} is true, then:
            <ol>
              <li>Add an array [<var>cachedRequest</var>, <var>cachedResponse</var>] to <var>resultArray</var>.</li>
              <li>Continue to the next iteration of the loop.</li>
            </ol>
          </li>
          <li>Let <var>varyHeaders</var> be the array containing the elements corresponding to the <a for="http">field-values</a> of the <a>Vary</a> header.</li>
          <li>Let <var>matchFailed</var> be false.</li>
          <li>For each <var>f</var> in <var>varyHeaders</var>:
            <ol>
              <li>If <var>f</var> matches "<code>*</code>", or the result of running <var>cachedRequest</var>.{{Request/headers}} object's {{Headers/get(name)}} method with <var>f</var> as the argument does not match the result of running <var>request</var>.{{Request/headers}} object's {{Headers/get(name)}} method with <var>f</var> as the argument, then:
                <ol>
                  <li>Set <var>matchFailed</var> to true.</li>
                  <li>Break the loop.</li>
                </ol>
              </li>
            </ol>
          </li>
          <li>If <var>matchFailed</var> is false, add an array [<var>cachedRequest</var>, <var>cachedResponse</var>] to <var>resultArray</var>.</li>
        </ol>
      </li>
      <li>Return <var>resultArray</var>.</li>
    </ol>
  </section>

  <section algorithm="batch-cache-operations-algorithm">
    <h3 id="batch-cache-operations-algorithm">Batch Cache Operations</h3>

    <dl>
      <dt>Input</dt>
        <dd><var>operations</var>, an array of  {{CacheBatchOperation}} dictionary objects</dd>
      <dt>Output</dt>
        <dd><var>promise</var>, a <a>promise</a> resolves with an array of {{Response}} objects.</dd>
    </dl>
    <ol>
      <li>Let <var>p</var> be a <a>promise</a> resolved with no value.</li>
      <li>Return the result of <a>transforming</a> <var>p</var> with a fulfillment handler that performs the following substeps <a>in parallel</a>:
        <ol>
          <li>Let <var>itemsCopy</var> be a new <a href="#dfn-request-to-response-map">request to response map</a> that is a copy of its <a>context object</a>'s <a href="#dfn-request-to-response-map">request to response map</a>.</li>
          <li>Let <var>addedRecords</var> be an empty array.</li>
          <li>Try running the following substeps atomically:
            <ol>
              <li>Let <var>resultArray</var> be an empty array.</li>
              <li>For each <var>operation</var> in <var>operations</var> with the index <var>index</var>:
                <ol>
                  <li>If <var>operation</var>.{{CacheBatchOperation/type}} matches neither "delete" nor "put", <a>throw</a> a <code>TypeError</code>.</li>
                  <li>If <var>operation</var>.{{CacheBatchOperation/type}} matches "delete" and <var>operation</var>.{{CacheBatchOperation/response}} is not null, <a>throw</a> a <code>TypeError</code>.</li>
                  <li>If the result of running <a href="#query-cache-algorithm">Query Cache</a> algorithm passing <var>operation</var>.{{CacheBatchOperation/request}}, <var>operation</var>.{{CacheBatchOperation/options}}, and <var>addedRecords</var> as the arguments is not an empty array, <a>throw</a> an "{{InvalidStateError}}" exception.</li>
                  <li>Let <var>requestResponseArray</var> be the result of running <a href="#query-cache-algorithm">Query Cache</a> algorithm passing <var>operation</var>.{{CacheBatchOperation/request}} and <var>operation</var>.{{CacheBatchOperation/options}} as the arguments.</li>
                  <li>For each <var>requestResponse</var> in <var>requestResponseArray</var>:
                    <ol>
                      <li>If <var>operation</var>.{{CacheBatchOperation/type}} matches "delete", remove the corresponding <a href="#dfn-fetching-record">fetching record</a> from <a href="#dfn-request-to-response-map">request to response map</a>.</li>
                    </ol>
                  </li>
                  <li>If <var>operation</var>.{{CacheBatchOperation/type}} matches "put", then:
                    <ol>
                      <li>If <var>operation</var>.{{CacheBatchOperation/response}} is null, <a>throw</a> a <code>TypeError</code>.</li>
                      <li>Let <var>r</var> be <var>operation</var>.{{CacheBatchOperation/request}}'s associated <a for="request">request</a>.</li>
                      <li>If <var>r</var>'s <a for="request">url</a>'s <a for="url">scheme</a> is not one of "<code>http</code>" and "<code>https</code>", <a>throw</a> a <code>TypeError</code>.</li>
                      <li>If <var>r</var>'s <a for="request">method</a> is not `<code>GET</code>`, <a>throw</a> a <code>TypeError</code>.</li>
                      <li>If <var>operation</var>.{{CacheBatchOperation/options}} is not null, <a>throw</a> a <code>TypeError</code>.</li>
                      <li>Set <var>requestResponseArray</var> to the result of running <a href="#query-cache-algorithm">Query Cache</a> algorithm passing <var>operation</var>.{{CacheBatchOperation/request}}.</li>
                      <li>If <var>requestResponseArray</var> is not an empty array, then:
                        <ol>
                          <li>Let <var>requestResponse</var> be <var>requestResponseArray</var>[0].</li>
                          <li>Let <var>fetchingRecord</var> be the corresponding <a href="#dfn-fetching-record">fetching record</a> for <var>requestResponse</var>[0] and <var>requestResponse</var>[1] in <a href="#dfn-request-to-response-map">request to response map</a>.</li>
                          <li>Set <var>fetchingRecord</var>.\[[key]] to <var>operation</var>.{{CacheBatchOperation/request}} and <var>fetchingRecord</var>.\[[value]] to <var>operation</var>.{{CacheBatchOperation/response}}.</li>
                        </ol>
                      </li>
                      <li>Else:
                        <ol>
                          <li>Set a newly-created <a href="#dfn-fetching-record">fetching record</a> {\[[key]]: <var>operation</var>.{{CacheBatchOperation/request}}, \[[value]]: <var>operation</var>.{{CacheBatchOperation/response}}} to <a href="#dfn-request-to-response-map">request to response map</a>.</li>
                        </ol>
                        <p class="note">The cache commit is allowed as long as the response's headers are available.</p>
                      </li>
                      <li>If the cache write operation in the previous two steps failed due to exceeding the granted quota limit, <a>throw</a> a "{{QuotaExceededError}}" exception.</li>
                      <li>Add an array [<var>operation</var>.<var>request</var>, <var>operation</var>.<var>response</var>] to <var>addedRecords</var>.</li>
                    </ol>
                  </li>
                  <li>Add <var>operation</var>.<var>response</var> to <var>resultArray</var>.</li>
                </ol>
              </li>
              <li>Return <var>resultArray</var>.</li>
            </ol>
          </li>
          <li>And then, if an exception was <a lt="throw">thrown</a>, then:
            <ol>
              <li>Set the <a>context object</a>'s <a href="#dfn-request-to-response-map">request to response map</a> to <var>itemsCopy</var>.</li>
              <li><a>Throw</a> the exception</li>
            </ol>
          </li>
        </ol>
      </li>
    </ol>
  </section>
</section>

<section>
  <h2 id="extended-http-headers">Appendix B: Extended HTTP headers</h2>

  <section>
    <h3 id="service-worker-script-request">Service Worker Script Request</h3>

    <p>An HTTP request to <a>fetch</a> a <a href="#dfn-service-worker">service worker</a>'s <a href="#dfn-script-resource">script resource</a> will include the following <a>header</a>:</p>

    <dl>
      <dt>`<dfn><code>Service-Worker</code></dfn>`</dt>
      <dd>Indicates this request is a <a href="#dfn-service-worker">service worker</a>'s <a href="#dfn-script-resource">script resource</a> request.
        <p class="note">This header helps administrators log the requests and detect threats.</p>
      </dd>
    </dl>
  </section>

  <section>
    <h3 id="service-worker-script-response">Service Worker Script Response</h3>

    <p>An HTTP response to a <a href="#dfn-service-worker">service worker</a>'s <a href="#dfn-script-resource">script resource</a> request can include the following <a>header</a>:</p>

    <dl>
      <dt>`<dfn><code>Service-Worker-Allowed</code></dfn>`</dt>
      <dd>Indicates the user agent will override the path restriction, which limits the maximum allowed <a href="#dfn-scope-url">scope url</a> that the script can <a href="#dfn-control">control</a>, to the given value.
        <p class="note">The value is a URL. If a relative URL is given, it is parsed against the script's URL.</p>
      </dd>
    </dl>

    <div class="example">
      Default scope:

      <pre class="lang-js">
// Maximum allowed scope defaults to the path the script sits in
// "/js" in this example
navigator.serviceWorker.register("/js/sw.js").then(function() {
  console.log("Install succeeded with the default scope '/js'.");
});
      </pre>
    </div>

    <div class="example">
      Upper path without Service-Worker-Allowed header:

      <pre class="lang-js">
// Set the scope to an upper path of the script location
// Response has no Service-Worker-Allowed header
navigator.serviceWorker.register("/js/sw.js", { scope: "/" }).catch(function() {
  console.error("Install failed due to the path restriction violation.");
});
      </pre>
    </div>

    <div class="example">
      Upper path with Service-Worker-Allowed header:

      <pre class="lang-js">
// Set the scope to an upper path of the script location
// Response included "Service-Worker-Allowed : /"
navigator.serviceWorker.register("/js/sw.js", { scope: "/" }).then(function() {
  console.log("Install succeeded as the max allowed scope was overriden to '/'.");
});
      </pre>
    </div>

    <div class="example">
      A path restriction voliation even with Service-Worker-Allowed header:

      <pre class="lang-js">
// Set the scope to an upper path of the script location
// Response included "Service-Worker-Allowed : /foo"
navigator.serviceWorker.register("/foo/bar/sw.js", { scope: "/" }).catch(function() {
  console.error("Install failed as the scope is still out of the overriden maximum allowed scope.");
});
      </pre>
    </div>
  </section>

  <section>
    <h3 id="syntax">Syntax</h3>

    <p><a biblio data-biblio-type="normative" lt="rfc5234">ABNF</a> for the values of the headers used by the <a href="#dfn-service-worker">service worker</a>'s <a href="#dfn-script-resource">script resource</a> requests and responses:</p>

    <pre>
    Service-Worker = %x73.63.72.69.70.74 ; "script", case-sensitive
    </pre>

    <p class="note">The validation of the Service-Worker-Allowed header's values is done by URL parsing algorithm (in Update algorithm) instead of using ABNF.</p>
  </section>
</section>

<section>
  <h2 id="acknowledgements">Acknowledgements</h2>
  <!-- FIXME: INCOMPLETE!! Please add collaborators below. -->
  <p>Deep thanks go to Andrew Betts for organizing and hosting a small workshop of like-minded individuals including: Jake Archibald, Jackson Gabbard, Tobie Langel, Robin Berjon, Patrick Lauke, Christian Heilmann. From the clarity of the day's discussions and the use-cases outlined there, much has become possible. Further thanks to Andrew for raising consciousness about the offline problem. His organization of EdgeConf and inclusion of Offline as a persistent topic there has created many opportunities and connections that have enabled this work to progress.</p>

  <p>Anne van Kesteren has generously lent his encyclopedic knowledge of Web Platform arcana and standards development experience throughout the development of the service worker. This specification would be incomplete without his previous work in describing the real-world behavior of URLs, HTTP Fetch, Promises, and DOM. Similarly, this specification would not be possible without Ian Hickson's rigorous Web Worker spec. Much thanks to him.</p>

  <p>In no particular order, deep gratitude for design guidance and discussion goes to: Jungkee Song, Alec Flett, David Barrett-Kahn, Aaron Boodman, Michael Nordman, Tom Ashworth, Kinuko Yasuda, Darin Fisher, Jonas Sicking, Jesús Leganés Combarro, Mark Christian, Dave Hermann, Yehuda Katz, François Remy, Ilya Grigorik, Will Chan, Domenic Denicola, Nikhil Marathe, Yves Lafon, Adam Barth, Greg Simon, Devdatta Akhawe, Dominic Cooney, Jeffrey Yasskin, Joshua Bell, Boris Zbarsky, Matt Falkenhagen, Tobie Langel, Gavin Peters, Ben Kelly, Hiroki Nakagawa, Jake Archibald, Josh Soref, Jinho Bang and Yutaka Hirano.</p>

  <p>Jason Weber, Chris Wilson, Paul Kinlan, Ehsan Akhgari, and Daniel Austin have provided valuable, well-timed feedback on requirements and the standardization process.</p>

  <p>The authors would also like to thank Dimitri Glazkov for his scripts and formatting tools which have been essential in the production of this specification. The authors are also grateful for his considerable guidance.</p>

  <p>Thanks also to Vivian Cromwell, Greg Simon, Alex Komoroske, Wonsuk Lee, and Seojin Kim for their considerable professional support.</p>
</section>
